chromium/ios/testing/earl_grey/base_earl_grey_test_case.mm

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/testing/earl_grey/base_earl_grey_test_case.h"

#import <UIKit/UIKit.h>
#import <objc/runtime.h>

#import "base/feature_list.h"
#import "base/logging.h"
#import "base/strings/sys_string_conversions.h"
#import "ios/testing/earl_grey/app_launch_configuration.h"
#import "ios/testing/earl_grey/app_launch_manager.h"
#import "ios/testing/earl_grey/base_earl_grey_test_case_app_interface.h"
#import "ios/testing/earl_grey/coverage_utils.h"
#import "ios/testing/earl_grey/earl_grey_test.h"
#import "ios/testing/earl_grey/system_alert_handler.h"

#if DCHECK_IS_ON()
#import "ui/display/screen_base.h"
#endif

namespace {

// If true, +setUpForTestCase will be called from -setUp.  This flag is used to
// ensure that +setUpForTestCase is called exactly once per unique XCTestCase
// and is reset in +tearDown.
bool g_needs_set_up_for_test_case = true;

}  // namespace

@implementation BaseEarlGreyTestCase

+ (void)setUpForTestCase {
}

+ (void)setUp {
  NSArray<NSString*>* blockedURLs = @[
    @".*app-measurement\\.com.*",
    @".*app-analytics-services\\.com.*",
  ];
  [[GREYConfiguration sharedConfiguration]
          setValue:blockedURLs
      forConfigKey:kGREYConfigKeyBlockedURLRegex];

  // Configuration for not tracking hidden animations. By default, all hidden
  // animations are tracked, and these sometimes cause flake. Set to YES so
  // tracking *should not* happen for hidden animations.
  [[GREYConfiguration sharedConfiguration]
          setValue:@YES
      forConfigKey:kGREYConfigKeyIgnoreHiddenAnimations];
}

// Invoked upon starting each test method in a test case.
// Launches the app under test if necessary.
- (void)setUp {
  [super setUp];

  [[AppLaunchManager sharedManager]
      ensureAppLaunchedWithConfiguration:[self appConfigurationForTestCase]];
  [SystemAlertHandler handleSystemAlertIfVisible];

  NSString* logFormat = @"*********************************\nStarting test: %@";
  [BaseEarlGreyTestCaseAppInterface
      logMessage:[NSString stringWithFormat:logFormat, self.name]];

  // Calling XCTFail before the application is launched does not assert
  // properly, so failing upon detection of overriding +setUp is delayed until
  // here. See +setUp below for details on why overriding +setUp causes a
  // failure.
  [self failIfSetUpIsOverridden];

  if (g_needs_set_up_for_test_case) {
    g_needs_set_up_for_test_case = false;
    [[self class] setUpForTestCase];
  }
}

+ (void)tearDown {
#if DCHECK_IS_ON()
  // The same screen object is shared across multiple test runs on IOS build.
  // Make sure that all display observers are removed at the end of each
  // test.
  if (display::Screen::HasScreen()) {
    display::ScreenBase* screen =
        static_cast<display::ScreenBase*>(display::Screen::GetScreen());
    DCHECK(!screen->HasDisplayObservers());
  }
#endif
  g_needs_set_up_for_test_case = true;
  [super tearDown];
}

- (AppLaunchConfiguration)appConfigurationForTestCase {
  return AppLaunchConfiguration();
}

#pragma mark - Private

// Prevents tests inheriting from this class from putting logic in +setUp.
// +setUp will be called before the application is launched,
// and thus is not suitable for most test case setup. Inheriting tests should
// migrate their +setUp logic to use the equivalent -setUpForTestCase.
- (void)failIfSetUpIsOverridden {
  if ([[BaseEarlGreyTestCase class] methodForSelector:@selector(setUp)] !=
      [[self class] methodForSelector:@selector(setUp)]) {
    XCTFail(@"EG2 test class %@ inheriting from BaseEarlGreyTestCase "
            @"should not override +setUp, as it is called before the "
            @"test application is launched. Please convert your "
            @"+setUp method to +setUpForTestCase.",
            NSStringFromClass([self class]));
  }
}

@end