Index: ios/chrome/test/earl_grey/chrome_test_case.mm |
diff --git a/ios/chrome/test/earl_grey/chrome_test_case.mm b/ios/chrome/test/earl_grey/chrome_test_case.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..1dfa8560aaaa7934270e6cf2c8fc5d96ec5b883f |
--- /dev/null |
+++ b/ios/chrome/test/earl_grey/chrome_test_case.mm |
@@ -0,0 +1,297 @@ |
+// Copyright 2016 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/test/earl_grey/chrome_test_case.h" |
+ |
+#import <objc/runtime.h> |
+ |
+#import <EarlGrey/EarlGrey.h> |
+ |
+#include "base/mac/scoped_block.h" |
+#include "base/strings/sys_string_conversions.h" |
+#import "ios/chrome/test/app/chrome_test_util.h" |
+#import "ios/chrome/test/app/settings_test_util.h" |
+#include "ios/chrome/test/app/signin_test_util.h" |
+#import "ios/chrome/test/app/sync_test_util.h" |
+#import "ios/chrome/test/app/tab_test_util.h" |
+#import "ios/web/public/test/http_server.h" |
+ |
+namespace { |
+ |
+// Contains a list of test names that run in multitasking test suite. |
+NSArray* whiteListedMultitaskingTests = @[ |
+ // Integration tests |
+ @"testContextMenuOpenInNewTab", // ContextMenuTestCase |
+ @"testSwitchToMain", // CookiesTestCase |
+ @"testSwitchToIncognito", // CookiesTestCase |
+ @"testFindDefaultFormAssistControls", // FormInputTestCase |
+ @"testTabDeletion", // TabUsageRecorderTestCase |
+ @"testAutoTranslate", // TranslateTestCase |
+ |
+ // Settings tests |
+ @"testSignInPopUpAccountOnSyncSettings", // AccountCollectionsTestCase |
+ @"testAutofillProfileEditing", // AutofillSettingsTestCase |
+ @"testAccessibilityOfBlockPopupSettings", // BlockPopupsTestCase |
+ @"testClearCookies", // SettingsTestCase |
+ @"testAccessibilityOfTranslateSettings", // TranslateUITestCase |
+ |
+ // UI tests |
+ @"testActivityServiceControllerPrintAfterRedirectionToUnprintablePage", |
+ // ActivityServiceControllerTestCase |
+ @"testDismissOnDestroy", // AlertCoordinatorTestCase |
+ @"testAddRemoveBookmark", // BookmarksTestCase |
+ @"testJavaScriptInOmnibox", // BrowserViewControllerTestCase |
+ @"testChooseCastReceiverChooser", // CastReceiverTestCase |
+ @"testErrorPage", // ErrorPageTestCase |
+ @"testFindInPage", // FindInPageTestCase |
+ @"testDismissFirstRun", // FirstRunTestCase |
+ @"testLongPDFScroll", // FullscreenTestCase |
+ @"testDeleteHistory", // HistoryUITestCase |
+ @"testInfobarsDismissOnNavigate", // InfobarTestCase |
+ @"testShowJavaScriptAlert", // JavaScriptDialogTestCase |
+ @"testKeyboardCommands_RecentTabsPresented", // KeyboardCommandsTestCase |
+ @"testAccessibilityOnMostVisited", // NewTabPageTestCase |
+ @"testPrintNormalPage", // PrintControllerTestCase |
+ @"testQRScannerUIIsShown", // QRScannerViewControllerTestCase |
+ @"testMarkMixedEntriesRead", // ReadingListTestCase |
+ @"testClosedTabAppearsInRecentTabsPanel", |
+ // RecentTabsPanelControllerTestCase |
+ @"testSafeModeSendingCrashReport", // SafeModeTestCase |
+ @"testSignInOneUser", // SigninInteractionControllerTestCase |
+ @"testSwitchTabs", // StackViewTestCase |
+ @"testTabStripSwitchTabs", // TabStripTestCase |
+ @"testTabHistoryMenu", // TabHistoryPopupControllerTestCase |
+ @"testEnteringTabSwitcher", // TabSwitcherControllerTestCase |
+ @"testEnterURL", // ToolbarTestCase |
+ @"testOpenAndCloseToolsMenu", // ToolsPopupMenuTestCase |
+ @"testUserFeedbackPageOpenPrivacyPolicy", // UserFeedbackTestCase |
+ @"testVersion", // WebUITestCase |
+]; |
+} // namespace |
+ |
+@interface ChromeTestCase () { |
+ // Block to be executed during object tearDown. |
+ base::mac::ScopedBlock<ProceduralBlock> _tearDownHandler; |
+ |
+ BOOL _isHTTPServerStopped; |
+ BOOL _isMockAuthenticationDisabled; |
+} |
+ |
+// Cleans up mock authentication. |
++ (void)disableMockAuthentication; |
+ |
+// Sets up mock authentication. |
++ (void)enableMockAuthentication; |
+ |
+// Stops the HTTP server. Should only be called when the server is running. |
++ (void)stopHTTPServer; |
+ |
+// Starts the HTTP server. Should only be called when the server is stopped. |
++ (void)startHTTPServer; |
+ |
+// Returns a NSArray of test names in this class that contain the prefix |
+// "FLAKY_". |
++ (NSArray*)flakyTestNames; |
+ |
+// Returns a NSArray of test names in this class for multitasking test suite. |
++ (NSArray*)multitaskingTestNames; |
+@end |
+ |
+@implementation ChromeTestCase |
+ |
+// Overrides testInvocations so the set of tests run can be modified, as |
+// necessary. |
++ (NSArray*)testInvocations { |
+ NSError* error = nil; |
+ [[EarlGrey selectElementWithMatcher:grey_systemAlertViewShown()] |
+ assertWithMatcher:grey_nil() |
+ error:&error]; |
+ if (error != nil) { |
+ NSLog(@"System alert view is present, so skipping all tests!"); |
+ return @[]; |
+ } |
+ |
+ // Return specific list of tests based on the target. |
+ NSString* targetName = [NSBundle mainBundle].infoDictionary[@"CFBundleName"]; |
+ if ([targetName isEqualToString:@"ios_chrome_flaky_egtests"]) { |
+ // Only run FLAKY_ tests for the flaky test suite. |
+ return [self flakyTestNames]; |
+ } else if ([targetName isEqualToString:@"ios_chrome_multitasking_egtests"]) { |
+ // Only run white listed tests for the multitasking test suite. |
+ return [self multitaskingTestNames]; |
+ } else { |
+ return [super testInvocations]; |
+ } |
+} |
+ |
+// Set up called once for the class, to dismiss anything displayed on startup |
+// and revert browser settings to default. It also starts the HTTP server and |
+// enables mock authentication. |
++ (void)setUp { |
+ [super setUp]; |
+ [[self class] startHTTPServer]; |
+ [[self class] enableMockAuthentication]; |
+ |
+ // Sometimes on start up there can be infobars (e.g. restore session), so |
+ // ensure the UI is in a clean state. |
+ [self removeAnyOpenMenusAndInfoBars]; |
+ [self closeAllTabs]; |
+ chrome_test_util::SetContentSettingsBlockPopups(CONTENT_SETTING_DEFAULT); |
+} |
+ |
+// Tear down called once for the class, to shutdown mock authentication and |
+// the HTTP server. |
++ (void)tearDown { |
+ [[self class] disableMockAuthentication]; |
+ [[self class] stopHTTPServer]; |
+ [super tearDown]; |
+} |
+ |
+// Set up called once per test, to open a new tab. |
+- (void)setUp { |
+ [super setUp]; |
+ _isHTTPServerStopped = NO; |
+ _isMockAuthenticationDisabled = NO; |
+ _tearDownHandler.reset(); |
+ |
+ chrome_test_util::OpenNewTab(); |
+ [[GREYUIThreadExecutor sharedInstance] drainUntilIdle]; |
+} |
+ |
+// Tear down called once per test, to close all tabs and menus, and clear the |
+// tracked tests accounts. It also makes sure mock authentication and the HTTP |
+// server are running. |
+- (void)tearDown { |
+ if (_tearDownHandler) { |
+ _tearDownHandler.get()(); |
+ } |
+ |
+ // Clear any remaining test accounts and signed in users. |
+ chrome_test_util::SignOutAndClearAccounts(); |
+ |
+ // Re-start anything that was disabled this test, so it is running when the |
+ // next test starts. |
+ if (_isHTTPServerStopped) { |
+ [[self class] startHTTPServer]; |
+ _isHTTPServerStopped = NO; |
+ } |
+ if (_isMockAuthenticationDisabled) { |
+ [[self class] enableMockAuthentication]; |
+ _isMockAuthenticationDisabled = NO; |
+ } |
+ |
+ // Clean up any UI that may remain open so the next test starts in a clean |
+ // state. |
+ [[self class] removeAnyOpenMenusAndInfoBars]; |
+ [[self class] closeAllTabs]; |
+ [super tearDown]; |
+} |
+ |
+#pragma mark - Public methods |
+ |
+- (void)setTearDownHandler:(ProceduralBlock)tearDownHandler { |
+ // Enforce that only one |_tearDownHandler| is set per test. |
+ DCHECK(!_tearDownHandler); |
+ _tearDownHandler.reset([tearDownHandler copy]); |
+} |
+ |
++ (void)removeAnyOpenMenusAndInfoBars { |
+ chrome_test_util::RemoveAllInfoBars(); |
+ chrome_test_util::ClearPresentedState(); |
+ // After programatically removing UI elements, allow Earl Grey's |
+ // UI synchronization to become idle, so subsequent steps won't start before |
+ // the UI is in a good state. |
+ [[GREYUIThreadExecutor sharedInstance] drainUntilIdle]; |
+} |
+ |
++ (void)closeAllTabs { |
+ chrome_test_util::CloseAllTabs(); |
+ [[GREYUIThreadExecutor sharedInstance] drainUntilIdle]; |
+} |
+ |
+- (void)disableMockAuthentication { |
+ // Enforce that disableMockAuthentication can only be called once. |
+ DCHECK(!_isMockAuthenticationDisabled); |
+ [[self class] disableMockAuthentication]; |
+ _isMockAuthenticationDisabled = YES; |
+} |
+ |
+- (void)stopHTTPServer { |
+ // Enforce that the HTTP server can only be stopped once per test. It should |
+ // not be stopped if it is not running. |
+ DCHECK(!_isHTTPServerStopped); |
+ [[self class] stopHTTPServer]; |
+ _isHTTPServerStopped = YES; |
+} |
+ |
+#pragma mark - Private methods |
+ |
++ (void)disableMockAuthentication { |
+ // Make sure local data is cleared, before disabling mock authentication, |
+ // where data may be sent to real servers. |
+ chrome_test_util::SignOutAndClearAccounts(); |
+ chrome_test_util::TearDownFakeSyncServer(); |
+ chrome_test_util::TearDownMockAccountReconcilor(); |
+ chrome_test_util::TearDownMockAuthentication(); |
+} |
+ |
++ (void)enableMockAuthentication { |
+ chrome_test_util::SetUpMockAuthentication(); |
+ chrome_test_util::SetUpMockAccountReconcilor(); |
+ chrome_test_util::SetUpFakeSyncServer(); |
+} |
+ |
++ (void)stopHTTPServer { |
+ web::test::HttpServer& server = web::test::HttpServer::GetSharedInstance(); |
+ DCHECK(server.IsRunning()); |
+ server.Stop(); |
+} |
+ |
++ (void)startHTTPServer { |
+ web::test::HttpServer& server = web::test::HttpServer::GetSharedInstance(); |
+ DCHECK(!server.IsRunning()); |
+ server.StartOrDie(); |
+} |
+ |
++ (NSArray*)flakyTestNames { |
+ const char kFlakyTestPrefix[] = "FLAKY"; |
+ unsigned int count = 0; |
+ Method* methods = class_copyMethodList(self, &count); |
+ NSMutableArray* flakyTestNames = [NSMutableArray array]; |
+ for (unsigned int i = 0; i < count; i++) { |
+ SEL selector = method_getName(methods[i]); |
+ if (std::string(sel_getName(selector)).find(kFlakyTestPrefix) == 0) { |
+ NSMethodSignature* methodSignature = |
+ [self instanceMethodSignatureForSelector:selector]; |
+ NSInvocation* invocation = |
+ [NSInvocation invocationWithMethodSignature:methodSignature]; |
+ invocation.selector = selector; |
+ [flakyTestNames addObject:invocation]; |
+ } |
+ } |
+ free(methods); |
+ return flakyTestNames; |
+} |
+ |
++ (NSArray*)multitaskingTestNames { |
+ unsigned int count = 0; |
+ Method* methods = class_copyMethodList(self, &count); |
+ NSMutableArray* multitaskingTestNames = [NSMutableArray array]; |
+ for (unsigned int i = 0; i < count; i++) { |
+ SEL selector = method_getName(methods[i]); |
+ if ([whiteListedMultitaskingTests |
+ containsObject:base::SysUTF8ToNSString(sel_getName(selector))]) { |
+ NSMethodSignature* methodSignature = |
+ [self instanceMethodSignatureForSelector:selector]; |
+ NSInvocation* invocation = |
+ [NSInvocation invocationWithMethodSignature:methodSignature]; |
+ invocation.selector = selector; |
+ [multitaskingTestNames addObject:invocation]; |
+ } |
+ } |
+ free(methods); |
+ return multitaskingTestNames; |
+} |
+ |
+@end |