blob: 711bd9026ff473d1a459b495e4f71aca9b8091e3 [file] [log] [blame]
// 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 "base/ios/ios_util.h"
#import "components/metrics/dwa/dwa_recorder.h"
#import "ios/chrome/browser/authentication/ui_bundled/signin_earl_grey.h"
#import "ios/chrome/browser/authentication/ui_bundled/signin_earl_grey_ui_test_util.h"
#import "ios/chrome/browser/metrics/model/metrics_app_interface.h"
#import "ios/chrome/browser/signin/model/fake_system_identity.h"
#import "ios/chrome/test/earl_grey/chrome_actions.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
#import "ios/chrome/test/earl_grey/chrome_matchers.h"
#import "ios/chrome/test/earl_grey/chrome_test_case.h"
#import "ios/testing/earl_grey/app_launch_configuration.h"
#import "ios/testing/earl_grey/earl_grey_test.h"
#import "net/test/embedded_test_server/default_handlers.h"
using chrome_test_util::GoogleServicesSettingsButton;
using chrome_test_util::SettingsDoneButton;
@interface DWATestCase : ChromeTestCase
@end
@implementation DWATestCase
+ (void)setUpForTestCase {
[super setUpForTestCase];
}
- (void)setUp {
[super setUp];
// These tests enable history synchronization via Recent Tabs.
// If the list contains too many tabs, the button at the bottom of
// the view moves offscreen, and its animation causes the tests to freeze,
// similar to crbug.com/640977.
if (![ChromeTestCase forceRestartAndWipe]) {
[ChromeEarlGrey clearBrowsingHistory];
}
GREYAssert([MetricsAppInterface checkDWARecordingEnabled:NO],
@"setUp: Failed to assert that DWA was not enabled.");
// Sign in to Chrome and enable history sync.
// Note: URL-keyed anonymized data collection is turned on as part of the
// flow to Sign in to Chrome and enable history sync. This matches the main
// user flow that enables DWA.
[SigninEarlGreyUI signinWithFakeIdentity:[FakeSystemIdentity fakeIdentity1]
enableHistorySync:YES];
[ChromeEarlGrey waitForSyncTransportStateActiveWithTimeout:
syncher::kSyncDWAOperationsTimeout];
// Grant metrics consent and update MetricsServicesManager.
[MetricsAppInterface overrideMetricsAndCrashReportingForTesting];
GREYAssert(![MetricsAppInterface setMetricsAndCrashReportingForTesting:YES],
@"setUp: Unpaired set/reset of user consent.");
GREYAssert([MetricsAppInterface checkDWARecordingEnabled:YES],
@"setUp: Failed to assert that DWA was enabled.");
GREYAssert([MetricsAppInterface DWARecorderAllowedForAllProfiles:YES],
@"setUp: Failed to assert that DWA was allowed for all profiles.");
net::test_server::RegisterDefaultHandlers(self.testServer);
GREYAssertTrue(self.testServer->Start(), @"Server did not start.");
}
- (void)tearDownHelper {
[ChromeEarlGrey waitForSyncTransportStateActiveWithTimeout:
syncher::kSyncDWAOperationsTimeout];
GREYAssert([MetricsAppInterface checkDWARecordingEnabled:YES],
@"tearDownHelper: Failed to assert that DWA was enabled.");
[MetricsAppInterface clearDWARecorder];
[self assertDwaRecorderIsEmpty];
// Revoke metrics consent and update MetricsServicesManager.
GREYAssert([MetricsAppInterface setMetricsAndCrashReportingForTesting:NO],
@"tearDownHelper: Unpaired set/reset of user consent.");
[MetricsAppInterface stopOverridingMetricsAndCrashReportingForTesting];
GREYAssert([MetricsAppInterface checkDWARecordingEnabled:NO],
@"tearDownHelper: Failed to assert that DWA was not enabled.");
// Sign out of Chrome.
// Note: URL-keyed anonymized data collection is turned off as part of the
// flow to Sign out of Chrome. This matches the main user flow that disables
// DWA.
[SigninEarlGrey signOut];
[ChromeEarlGrey clearFakeSyncServerData];
[super tearDownHelper];
}
// Enable the DWA feature
- (AppLaunchConfiguration)appConfigurationForTestCase {
AppLaunchConfiguration config = [super appConfigurationForTestCase];
config.features_enabled.push_back(metrics::dwa::kDwaFeature);
return config;
}
#pragma mark - Helpers
// Waits for a new incognito tab to be opened.
- (void)openNewIncognitoTab {
const NSUInteger incognitoTabCount = [ChromeEarlGrey incognitoTabCount];
[ChromeEarlGrey openNewIncognitoTab];
[ChromeEarlGrey waitForIncognitoTabCount:(incognitoTabCount + 1)];
GREYAssert([ChromeEarlGrey isIncognitoMode],
@"openNewIncognitoTab: Failed to switch to incognito mode.");
}
// Waits for the current incognito tab to be closed.
- (void)closeCurrentIncognitoTab {
const NSUInteger incognitoTabCount = [ChromeEarlGrey incognitoTabCount];
[ChromeEarlGrey closeCurrentTab];
[ChromeEarlGrey waitForIncognitoTabCount:(incognitoTabCount - 1)];
}
// Waits for all incognito tabs to be closed.
- (void)closeAllIncognitoTabs {
[ChromeEarlGrey closeAllIncognitoTabs];
[ChromeEarlGrey waitForIncognitoTabCount:0];
// The user is dropped into the tab grid after closing the last incognito tab.
// Therefore this test must manually switch back to showing the normal tabs.
[[EarlGrey
selectElementWithMatcher:chrome_test_util::TabGridOpenTabsPanelButton()]
performAction:grey_tap()];
[[EarlGrey selectElementWithMatcher:chrome_test_util::TabGridDoneButton()]
performAction:grey_tap()];
GREYAssert(![ChromeEarlGrey isIncognitoMode],
@"closeAllIncognitoTabs: Failed to switch to normal mode.");
}
// Waits for a new tab to be opened.
- (void)openNewRegularTab {
const NSUInteger tabCount = [ChromeEarlGrey mainTabCount];
[ChromeEarlGrey openNewTab];
[ChromeEarlGrey waitForMainTabCount:(tabCount + 1)];
}
// Toggle "Make searches and browsing better" switch on.
- (void)turnOnMsbbSwitch {
// Wait for the Msbb switch to appear.
[ChromeEarlGrey waitForUIElementToAppearWithMatcher:
chrome_test_util::TableViewSwitchCell(
@"betterSearchAndBrowsingItem_switch", NO)];
[[EarlGrey
selectElementWithMatcher:chrome_test_util::TableViewSwitchCell(
@"betterSearchAndBrowsingItem_switch", NO)]
performAction:chrome_test_util::TurnTableViewSwitchOn(YES)];
}
// Toggle "Make searches and browsing better" switch off.
- (void)turnOffMsbbSwitch {
[ChromeEarlGrey waitForUIElementToAppearWithMatcher:
chrome_test_util::TableViewSwitchCell(
@"betterSearchAndBrowsingItem_switch", YES)];
[[EarlGrey
selectElementWithMatcher:chrome_test_util::TableViewSwitchCell(
@"betterSearchAndBrowsingItem_switch", YES)]
performAction:chrome_test_util::TurnTableViewSwitchOn(NO)];
}
// Assertions to check that the DWA recorder is enabled and allowed for all
// profiles.
- (void)assertDwaIsEnabledAndAllowed {
GREYAssert([MetricsAppInterface checkDWARecordingEnabled:YES],
@"Failed to assert that DWA was enabled.");
GREYAssert([MetricsAppInterface DWARecorderAllowedForAllProfiles:YES],
@"Failed to assert that DWA was "
@"allowed for all profiles.");
}
// Assertions to check that the DWA recorder has entries.
- (void)assertDwaRecorderHasMetrics {
GREYAssert([MetricsAppInterface DWARecorderHasEntries:YES],
@"DWA Recorder should have "
@"entries.");
}
// Assertions to check that the DWA recorder is not enabled and not allowed for
// all profiles.
- (void)assertDwaIsDisabledAndDisallowed {
GREYAssert([MetricsAppInterface checkDWARecordingEnabled:NO],
@"Failed to assert that DWA was not enabled.");
GREYAssert([MetricsAppInterface DWARecorderAllowedForAllProfiles:NO],
@"Failed to assert that DWA was not "
@"allowed for all profiles.");
}
// Assertions to check that the DWA recorder has no entries.
- (void)assertDwaRecorderIsEmpty {
GREYAssert([MetricsAppInterface DWARecorderHasEntries:NO],
@"DWA Recorder should not have any "
@"entries.");
}
#pragma mark - Tests
// The tests in this file should correspond to the tests in
// //chrome/browser/metrics/dwa_browsertest.cc
// LINT.IfChange(DwaServiceCheck)
- (void)testDwaServiceCheck {
// [Note: Tests begin with an open regular tab. This tab is opened in setUp.
// DWA should be enabled with first regular browser.
GREYAssert([MetricsAppInterface checkDWARecordingEnabled:YES],
@"Failed to assert that DWA was enabled.");
// Records a DWA entry metric.
[MetricsAppInterface recordTestDWAEntryMetric];
GREYAssert([MetricsAppInterface hasUnsentDWALogs:NO],
@"DWA Service should not have unsent logs.");
[MetricsAppInterface DWAServiceFlushCall];
[self assertDwaRecorderIsEmpty];
GREYAssert([MetricsAppInterface hasUnsentDWALogs:YES],
@"DWA Service should have unsent logs.");
}
// LINT.ThenChange(/chrome/browser/metrics/dwa_browsertest.cc:DwaServiceCheck)
// Make sure that DWA is disabled and purged while an incognito window is open.
// LINT.IfChange(RegularBrowserPlusIncognitoCheck)
- (void)testRegularBrowserPlusIncognitoCheck {
// Note: Tests begin with an open regular tab. This tab is opened in setUp.
// DWA should be enabled with first regular browser.
GREYAssert([MetricsAppInterface checkDWARecordingEnabled:YES],
@"Failed to assert that DWA "
@"was enabled.");
[MetricsAppInterface recordTestDWAEntryMetric];
GREYAssert([MetricsAppInterface DWARecorderHasEntries:YES],
@"Failed to record test "
@"entry metric.");
// Opening an incognito browser should disable DwaRecorder and metrics
// should be purged.
[self openNewIncognitoTab];
GREYAssert([MetricsAppInterface checkDWARecordingEnabled:NO],
@"Failed to assert that DWA "
@"was not enabled.");
GREYAssert([MetricsAppInterface DWARecorderHasEntries:NO],
@"DWA Recorder should not "
@"have any entries.");
[MetricsAppInterface recordTestDWAEntryMetric];
GREYAssert([MetricsAppInterface DWARecorderHasEntries:NO],
@"DWA Recorder should not "
@"have any entries.");
// Opening another regular tab mustn't enabled DWA.
[self openNewRegularTab];
GREYAssert([MetricsAppInterface checkDWARecordingEnabled:NO],
@"Failed to assert that DWA was not enabled.");
[MetricsAppInterface recordTestDWAEntryMetric];
GREYAssert([MetricsAppInterface DWARecorderHasEntries:NO],
@"DWA Recorder should not "
@"have any entries.");
// Opening and closing another incognito browser must not enable DWA.
[self openNewIncognitoTab];
GREYAssert([MetricsAppInterface checkDWARecordingEnabled:NO],
@"Failed to assert that DWA was not enabled.");
[MetricsAppInterface recordTestDWAEntryMetric];
GREYAssert([MetricsAppInterface DWARecorderHasEntries:NO],
@"DWA Recorder should not "
@"have any entries.");
[self closeCurrentIncognitoTab];
GREYAssert([MetricsAppInterface checkDWARecordingEnabled:NO],
@"Failed to assert that DWA was not enabled.");
[MetricsAppInterface recordTestDWAEntryMetric];
GREYAssert([MetricsAppInterface DWARecorderHasEntries:NO],
@"DWA Recorder should not "
@"have any entries.");
// TODO(crbug.com/41271925): Due to continuous animations, it is not feasible
// (i) to use the tab switcher to switch between modes or (ii) to omit the
// below code block and simply call [ChromeEarlGrey closeAllIncognitoTabs];
// from incognito mode.
[self openNewRegularTab];
[ChromeEarlGrey closeCurrentTab];
[ChromeEarlGrey closeCurrentTab];
GREYAssert([MetricsAppInterface checkDWARecordingEnabled:NO],
@"Failed to assert that DWA "
@"was not enabled.");
[MetricsAppInterface recordTestDWAEntryMetric];
GREYAssert([MetricsAppInterface DWARecorderHasEntries:NO],
@"DWA Recorder should not "
@"have any entries.");
// At this point, there is one open regular tab and one open incognito tab.
[ChromeEarlGrey closeAllIncognitoTabs];
// All incognito tabs have been closed, so DWA should be enabled.
GREYAssert([MetricsAppInterface checkDWARecordingEnabled:YES],
@"Failed to assert that DWA "
@"was enabled.");
GREYAssert([MetricsAppInterface DWARecorderHasEntries:NO],
@"DWA Recorder should not "
@"have any entries.");
[MetricsAppInterface recordTestDWAEntryMetric];
GREYAssert([MetricsAppInterface DWARecorderHasEntries:YES],
@"Failed to record test "
@"entry metric.");
}
// LINT.ThenChange(/chrome/browser/metrics/dwa_browsertest.cc:RegularBrowserPlusIncognitoCheck)
// Make sure opening a regular browser after Incognito doesn't enable DWA.
// LINT.IfChange(IncognitoBrowserPlusRegularCheck)
- (void)testIncognitoBrowserPlusRegularCheck {
// Note: Tests begin with an open regular tab. This tab is opened in setUp.
// TODO(crbug.com/41271925): Due to continuous animations, it is not feasible
// to close the regular tab that is already open. The functions closeAllTabs,
// closeCurrentTab, and closeAllTabsInCurrentMode close the tab and then hang.
// As a workaround, we open an incognito tab and then close the regular tab to
// get to a state in which a single incognito tab is open.
// Opening an incognito browser should disable DwaRecorder and metrics should
// be purged.
[self openNewIncognitoTab];
[ChromeEarlGrey closeAllNormalTabs];
GREYAssert([MetricsAppInterface checkDWARecordingEnabled:NO],
@"Failed to assert that DWA was not enabled.");
// Opening another regular browser must not enable DWA.
[self openNewRegularTab];
GREYAssert([MetricsAppInterface checkDWARecordingEnabled:NO],
@"Failed to assert that DWA was not enabled.");
// All incognito tabs have been closed, so DWA should be enabled.
[ChromeEarlGrey closeAllIncognitoTabs];
GREYAssert([MetricsAppInterface checkDWARecordingEnabled:YES],
@"Failed to assert that DWA was enabled.");
}
// LINT.ThenChange(/chrome/browser/metrics/dwa_browsertest.cc:IncognitoBrowserPlusRegularCheck)
// Tests that disabling MSBB UKM consent disables and purges DWA.
// Additionally tests that DWA is disabled until all UKM consents are enabled.
// LINT.IfChange(UkmMsbbConsentChangeCheck)
- (void)testUkmMsbbConsentChangeCheck {
// Note: Tests begin with an open regular tab. This tab is opened in setUp.
[MetricsAppInterface recordTestDWAEntryMetric];
[self assertDwaIsEnabledAndAllowed];
[self assertDwaRecorderHasMetrics];
[ChromeEarlGreyUI openSettingsMenu];
[ChromeEarlGrey waitForSufficientlyVisibleElementWithMatcher:
GoogleServicesSettingsButton()];
// Open Google services settings.
[ChromeEarlGreyUI tapSettingsMenuButton:GoogleServicesSettingsButton()];
[ChromeEarlGreyUI waitForAppToIdle];
// Toggle "Make searches and browsing better" switch off.
[self turnOffMsbbSwitch];
[self assertDwaIsDisabledAndDisallowed];
[self assertDwaRecorderIsEmpty];
// Toggle "Make searches and browsing better" switch on.
[self turnOnMsbbSwitch];
[self assertDwaIsEnabledAndAllowed];
[self assertDwaRecorderIsEmpty];
// Validate DWA entries is able to be recorded when all consents are enabled.
[MetricsAppInterface recordTestDWAEntryMetric];
[self assertDwaRecorderHasMetrics];
[[EarlGrey selectElementWithMatcher:SettingsDoneButton()]
performAction:grey_tap()];
}
// LINT.ThenChange(/chrome/browser/metrics/dwa_browsertest.cc:UkmMsbbConsentChangeCheck)
@end