blob: 8d9ba474ecc24d10519065788656830374024f5a [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#import "base/ios/ios_util.h"
#import "base/test/ios/wait_util.h"
#import "components/strings/grit/components_chromium_strings.h"
#import "ios/chrome/browser/overlays/public/web_content_area/alert_constants.h"
#import "ios/chrome/browser/ui/page_info/page_info_constants.h"
#import "ios/chrome/browser/ui/permissions/permissions_app_interface.h"
#import "ios/chrome/browser/ui/permissions/permissions_constants.h"
#import "ios/chrome/grit/ios_chromium_strings.h"
#import "ios/chrome/grit/ios_strings.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/earl_grey_test.h"
#import "ios/web/public/permissions/permissions.h"
#import "net/test/embedded_test_server/embedded_test_server.h"
#import "ui/base/l10n/l10n_util.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
using ::base::test::ios::kWaitForUIElementTimeout;
using ::base::test::ios::WaitUntilConditionOrTimeout;
// Matcher infobar modal camera permissions switch.
id<GREYMatcher> CameraPermissionsSwitch(BOOL isOn) {
return chrome_test_util::TableViewSwitchCell(
kPageInfoCameraSwitchAccessibilityIdentifier, isOn);
}
// Matcher infobar modal microphone permissions switch.
id<GREYMatcher> MicrophonePermissionsSwitch(BOOL isOn) {
return chrome_test_util::TableViewSwitchCell(
kPageInfoMicrophoneSwitchAccessibilityIdentifier, isOn);
}
} // namespace
@interface PageInfoTestCase : ChromeTestCase
@end
@implementation PageInfoTestCase
// Checks that if the alert for site permissions pops up, and allow it.
- (void)checkAndAllowPermissionAlerts {
// Allow system permission if shown.
NSError* systemAlertFoundError = nil;
[[EarlGrey selectElementWithMatcher:grey_systemAlertViewShown()]
assertWithMatcher:grey_nil()
error:&systemAlertFoundError];
if (systemAlertFoundError) {
NSError* acceptAlertError = nil;
[self grey_acceptSystemDialogWithError:&acceptAlertError];
GREYAssertNil(acceptAlertError, @"Error accepting system alert.\n%@",
acceptAlertError);
}
// Allow site permission.
id<GREYMatcher> dialogMatcher =
grey_accessibilityID(kPermissionsDialogAccessibilityIdentifier);
ConditionBlock condition = ^{
NSError* error = nil;
[[EarlGrey selectElementWithMatcher:dialogMatcher]
assertWithMatcher:grey_sufficientlyVisible()
error:&error];
return !error;
};
GREYAssert(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, condition),
@"Permissions dialog was not shown.");
NSString* allowButtonText = l10n_util::GetNSString(
IDS_IOS_PERMISSIONS_ALERT_DIALOG_BUTTON_TEXT_GRANT);
// TODO(crbug.com/1418068): Simplify after minimum version required is >=
// iOS 15.
id<GREYMatcher> allowButtonMatcher = nil;
if (base::ios::IsRunningOnIOS15OrLater() &&
[ChromeEarlGrey isUIButtonConfigurationEnabled]) {
allowButtonMatcher = grey_allOf(grey_ancestor(dialogMatcher),
grey_accessibilityLabel(allowButtonText),
grey_kindOfClassName(@"UILabel"), nil);
} else {
allowButtonMatcher =
grey_allOf(grey_ancestor(dialogMatcher),
grey_accessibilityLabel(allowButtonText), nil);
}
[[[EarlGrey selectElementWithMatcher:allowButtonMatcher]
assertWithMatcher:grey_sufficientlyVisible()] performAction:grey_tap()];
}
// Checks `expectedStatesForPermissions` matches the actual states for
// permissions of the active web state; checks will fail if there is no active
// web state.
- (void)checkStatesForPermissions:
(NSDictionary<NSNumber*, NSNumber*>*)expectedStatesForPermissions
API_AVAILABLE(ios(15.0)) {
NSDictionary<NSNumber*, NSNumber*>* actualStatesForPermissions =
[PermissionsAppInterface statesForAllPermissions];
GREYAssertEqualObjects(
expectedStatesForPermissions[@(web::PermissionCamera)],
actualStatesForPermissions[@(web::PermissionCamera)],
@"Camera state: %@ does not match expected: %@.",
actualStatesForPermissions[@(web::PermissionCamera)],
expectedStatesForPermissions[@(web::PermissionCamera)]);
GREYAssertEqualObjects(
expectedStatesForPermissions[@(web::PermissionMicrophone)],
actualStatesForPermissions[@(web::PermissionMicrophone)],
@"Microphone state: %@ does not match expected: %@.",
actualStatesForPermissions[@(web::PermissionMicrophone)],
expectedStatesForPermissions[@(web::PermissionMicrophone)]);
}
// Tests that rotating the device will don't dismiss the page info view.
- (void)testShowPageInfoRotation {
GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
[ChromeEarlGrey loadURL:self.testServer->GetURL("/")];
[ChromeEarlGreyUI openPageInfo];
// Checks that the page info view has appeared.
[[EarlGrey selectElementWithMatcher:grey_accessibilityID(
kPageInfoViewAccessibilityIdentifier)]
assertWithMatcher:grey_sufficientlyVisible()];
// Rotates the device and checks that the page info view is still presented.
[EarlGrey rotateDeviceToOrientation:UIDeviceOrientationLandscapeRight
error:nil];
[[EarlGrey selectElementWithMatcher:grey_accessibilityID(
kPageInfoViewAccessibilityIdentifier)]
assertWithMatcher:grey_sufficientlyVisible()];
// Closes the page info using the 'Done' button.
[[EarlGrey
selectElementWithMatcher:chrome_test_util::NavigationBarDoneButton()]
performAction:grey_tap()];
[[EarlGrey selectElementWithMatcher:grey_accessibilityID(
kPageInfoViewAccessibilityIdentifier)]
assertWithMatcher:grey_nil()];
}
// Tests that opening the page info on a Chromium page displays the correct
// information.
- (void)testShowPageInfoChromePage {
[ChromeEarlGrey loadURL:GURL("chrome://version")];
[ChromeEarlGreyUI openPageInfo];
// Checks that the page info view has appeared.
[[EarlGrey selectElementWithMatcher:grey_accessibilityID(
kPageInfoViewAccessibilityIdentifier)]
assertWithMatcher:grey_sufficientlyVisible()];
// Checks that “You’re viewing a secure Chrome page.” is displayed.
[[EarlGrey selectElementWithMatcher:grey_text(l10n_util::GetNSString(
IDS_PAGE_INFO_INTERNAL_PAGE))]
assertWithMatcher:grey_sufficientlyVisible()];
}
// Tests that the Permissions section is not displayed, as there isn't any
// accessible permissions.
- (void)testShowPageInfoWithNoAccessiblePermission {
if (@available(iOS 15.0, *)) {
GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
[ChromeEarlGrey loadURL:self.testServer->GetURL("/")];
[ChromeEarlGreyUI openPageInfo];
// Checks that permission header is not visible.
[[EarlGrey
selectElementWithMatcher:grey_text(l10n_util::GetNSString(
IDS_IOS_PAGE_INFO_PERMISSIONS_HEADER))]
assertWithMatcher:grey_notVisible()];
}
}
// Tests that single accessible permission is shown in Permissions section with
// toggle.
// TODO(crbug.com/1316705): Test fails on device due to asking for microphone
// permission.
#if !TARGET_IPHONE_SIMULATOR
#define MAYBE_testShowOneAccessiblePermissionInPageInfo \
DISABLED_testShowOneAccessiblePermissionInPageInfo
#else
#define MAYBE_testShowOneAccessiblePermissionInPageInfo \
testShowOneAccessiblePermissionInPageInfo
#endif
- (void)MAYBE_testShowOneAccessiblePermissionInPageInfo {
if (@available(iOS 15.0, *)) {
// Open a page that requests microphone permissions.
GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
[ChromeEarlGrey
loadURL:self.testServer->GetURL("/permissions/microphone_only.html")];
[self checkAndAllowPermissionAlerts];
// Check that permission header is visible.
[ChromeEarlGreyUI openPageInfo];
[[EarlGrey
selectElementWithMatcher:grey_text(l10n_util::GetNSString(
IDS_IOS_PAGE_INFO_PERMISSIONS_HEADER))]
assertWithMatcher:grey_sufficientlyVisible()];
// Check that camera permission item is hidden, and in accordance with the
// web state permission states.
[self checkStatesForPermissions:@{
@(web::PermissionCamera) : @(web::PermissionStateNotAccessible),
@(web::PermissionMicrophone) : @(web::PermissionStateAllowed)
}];
[[EarlGrey
selectElementWithMatcher:grey_anyOf(CameraPermissionsSwitch(YES),
CameraPermissionsSwitch(NO), nil)]
assertWithMatcher:grey_notVisible()];
// Check that microphone permission item is visible, and turn it off.
[[EarlGrey selectElementWithMatcher:MicrophonePermissionsSwitch(YES)]
performAction:chrome_test_util::TurnTableViewSwitchOn(NO)];
[[EarlGrey // Dismiss view.
selectElementWithMatcher:grey_accessibilityID(
kPageInfoViewAccessibilityIdentifier)]
performAction:grey_swipeFastInDirection(kGREYDirectionDown)];
[self checkStatesForPermissions:@{
@(web::PermissionCamera) : @(web::PermissionStateNotAccessible),
@(web::PermissionMicrophone) : @(web::PermissionStateBlocked)
}];
}
}
// Tests that two accessible permissions are shown in Permissions section with
// toggle.
// TODO(crbug.com/1316705): Test fails on device due to asking for microphone
// permission.
#if !TARGET_IPHONE_SIMULATOR
#define MAYBE_testShowTwoAccessiblePermissionsInPageInfo \
DISABLED_testShowTwoAccessiblePermissionsInPageInfo
#else
#define MAYBE_testShowTwoAccessiblePermissionsInPageInfo \
testShowTwoAccessiblePermissionsInPageInfo
#endif
- (void)MAYBE_testShowTwoAccessiblePermissionsInPageInfo {
if (@available(iOS 15.0, *)) {
// Open a page that requests microphone permissions.
GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
[ChromeEarlGrey loadURL:self.testServer->GetURL(
"/permissions/camera_and_microphone.html")];
[self checkAndAllowPermissionAlerts];
// Check that permission header is visible.
[ChromeEarlGreyUI openPageInfo];
[[EarlGrey
selectElementWithMatcher:grey_text(l10n_util::GetNSString(
IDS_IOS_PAGE_INFO_PERMISSIONS_HEADER))]
assertWithMatcher:grey_sufficientlyVisible()];
// Check that switchs for both permissions are visible.
[self checkStatesForPermissions:@{
@(web::PermissionCamera) : @(web::PermissionStateAllowed),
@(web::PermissionMicrophone) : @(web::PermissionStateAllowed)
}];
// Check that both permission item is visible, and turn off camera
// permission.
[[EarlGrey selectElementWithMatcher:MicrophonePermissionsSwitch(YES)]
assertWithMatcher:grey_sufficientlyVisible()];
[[EarlGrey selectElementWithMatcher:CameraPermissionsSwitch(YES)]
performAction:chrome_test_util::TurnTableViewSwitchOn(NO)];
[[EarlGrey // Dismiss view.
selectElementWithMatcher:grey_accessibilityID(
kPageInfoViewAccessibilityIdentifier)]
performAction:grey_swipeFastInDirection(kGREYDirectionDown)];
[self checkStatesForPermissions:@{
@(web::PermissionCamera) : @(web::PermissionStateBlocked),
@(web::PermissionMicrophone) : @(web::PermissionStateAllowed)
}];
}
}
// Tests that rotating the device will not dismiss the navigation bar.
- (void)testShowPageInfoTitleRotation {
GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
[ChromeEarlGrey loadURL:self.testServer->GetURL("/")];
[ChromeEarlGreyUI openPageInfo];
// Check that the navigation bar is visible.
[[EarlGrey selectElementWithMatcher:
grey_accessibilityID(
kPageInfoViewNavigationBarAccessibilityIdentifier)]
assertWithMatcher:grey_sufficientlyVisible()];
// Rotate to landscape mode and check the navigation bar is still visible.
[EarlGrey rotateDeviceToOrientation:UIDeviceOrientationLandscapeRight
error:nil];
[[EarlGrey selectElementWithMatcher:
grey_accessibilityID(
kPageInfoViewNavigationBarAccessibilityIdentifier)]
assertWithMatcher:grey_sufficientlyVisible()];
// Rotate back to portrait mode and check the navigation bar is still visible.
[EarlGrey rotateDeviceToOrientation:UIDeviceOrientationPortrait error:nil];
[[EarlGrey selectElementWithMatcher:
grey_accessibilityID(
kPageInfoViewNavigationBarAccessibilityIdentifier)]
assertWithMatcher:grey_sufficientlyVisible()];
}
@end