Commit 959cddb1 authored by Javier Ernesto Flores Robles's avatar Javier Ernesto Flores Robles Committed by Commit Bot

[iOS][MF][EG2] Migrate keyboard observer test

Remove deprecate test that would require new code to be migrated.
Update and enable keyboard disappear test.
Create app interface to interact with a shared instance of the observer
in the app.
Remove OCMock usage in the test.

TBR=eugenebut@chromium.org

Change-Id: Iaa5384f241e63b95ee516d4666b2e2adf65b7da6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1881566
Commit-Queue: Javier Ernesto Flores Robles <javierrobles@chromium.org>
Reviewed-by: default avatarJavier Ernesto Flores Robles <javierrobles@chromium.org>
Reviewed-by: default avatarStepan Khapugin <stkhapugin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#709939}
parent c1176485
...@@ -216,6 +216,7 @@ source_set("eg_tests") { ...@@ -216,6 +216,7 @@ source_set("eg_tests") {
"//ios/chrome/browser/ui/settings/autofill:feature_flags", "//ios/chrome/browser/ui/settings/autofill:feature_flags",
"//ios/chrome/browser/ui/settings/password", "//ios/chrome/browser/ui/settings/password",
"//ios/chrome/browser/ui/util", "//ios/chrome/browser/ui/util",
"//ios/chrome/browser/ui/util:test_support",
"//ios/chrome/test:eg_test_support", "//ios/chrome/test:eg_test_support",
"//ios/chrome/test/app:test_support", "//ios/chrome/test/app:test_support",
"//ios/chrome/test/earl_grey:test_support", "//ios/chrome/test/earl_grey:test_support",
...@@ -224,7 +225,6 @@ source_set("eg_tests") { ...@@ -224,7 +225,6 @@ source_set("eg_tests") {
"//ios/web:earl_grey_test_support", "//ios/web:earl_grey_test_support",
"//ios/web/public/test:element_selector", "//ios/web/public/test:element_selector",
"//ios/web/public/test/http_server", "//ios/web/public/test/http_server",
"//third_party/ocmock",
] ]
} }
...@@ -240,6 +240,7 @@ source_set("eg2_tests") { ...@@ -240,6 +240,7 @@ source_set("eg2_tests") {
"card_view_controller_egtest.mm", "card_view_controller_egtest.mm",
"fallback_coordinator_egtest.mm", "fallback_coordinator_egtest.mm",
"fallback_view_controller_egtest.mm", "fallback_view_controller_egtest.mm",
"keyboard_observer_egtest.mm",
"password_view_controller_egtest.mm", "password_view_controller_egtest.mm",
] ]
deps = [ deps = [
...@@ -248,6 +249,9 @@ source_set("eg2_tests") { ...@@ -248,6 +249,9 @@ source_set("eg2_tests") {
"//ios/chrome/app/strings:ios_strings_grit", "//ios/chrome/app/strings:ios_strings_grit",
"//ios/chrome/browser/ui/autofill:eg_test_support+eg2", "//ios/chrome/browser/ui/autofill:eg_test_support+eg2",
"//ios/chrome/browser/ui/settings/autofill:feature_flags", "//ios/chrome/browser/ui/settings/autofill:feature_flags",
"//ios/chrome/browser/ui/util",
"//ios/chrome/browser/ui/util:eg_test_support+eg2",
"//ios/chrome/test:eg_test_support+eg2",
"//ios/chrome/test/earl_grey:eg_test_support+eg2", "//ios/chrome/test/earl_grey:eg_test_support+eg2",
"//ios/testing/earl_grey:eg_test_support+eg2", "//ios/testing/earl_grey:eg_test_support+eg2",
"//ios/third_party/earl_grey2:test_lib", "//ios/third_party/earl_grey2:test_lib",
......
...@@ -2,30 +2,34 @@ ...@@ -2,30 +2,34 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#import <EarlGrey/EarlGrey.h>
#import <EarlGrey/GREYKeyboard.h>
#include "base/mac/foundation_util.h" #include "base/mac/foundation_util.h"
#include "base/strings/sys_string_conversions.h" #include "base/strings/sys_string_conversions.h"
#import "base/test/ios/wait_util.h" #import "base/test/ios/wait_util.h"
#import "ios/chrome/browser/ui/util/keyboard_observer_helper.h" #import "ios/chrome/browser/ui/util/keyboard_observer_helper.h"
#import "ios/chrome/test/app/chrome_test_util.h" #import "ios/chrome/browser/ui/util/keyboard_observer_helper_app_interface.h"
#import "ios/chrome/test/app/tab_test_util.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.h"
#import "ios/chrome/test/earl_grey/chrome_matchers.h" #import "ios/chrome/test/earl_grey/chrome_matchers.h"
#import "ios/chrome/test/earl_grey/chrome_test_case.h" #import "ios/chrome/test/earl_grey/chrome_test_case.h"
#import "ios/chrome/test/scoped_eg_synchronization_disabler.h" #import "ios/chrome/test/scoped_eg_synchronization_disabler.h"
#import "ios/web/public/test/earl_grey/web_view_actions.h" #import "ios/testing/earl_grey/earl_grey_test.h"
#import "ios/web/public/test/earl_grey/web_view_matchers.h"
#include "ios/web/public/test/element_selector.h"
#import "ios/web/public/test/http_server/http_server.h"
#include "ios/web/public/test/http_server/http_server_util.h"
#import "third_party/ocmock/OCMock/OCMock.h"
#if !defined(__has_feature) || !__has_feature(objc_arc) #if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support." #error "This file requires ARC support."
#endif #endif
#if defined(CHROME_EARL_GREY_2)
// TODO(crbug.com/1015113): The EG2 macro is breaking indexing for some reason
// without the trailing semicolon. For now, disable the extra semi warning
// so Xcode indexing works for the egtest.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wc++98-compat-extra-semi"
GREY_STUB_CLASS_IN_APP_MAIN_QUEUE(KeyboardObserverHelperAppInterface);
#pragma clang diagnostic pop
#endif // defined(CHROME_EARL_GREY_2)
using base::test::ios::WaitUntilConditionOrTimeout;
using chrome_test_util::TapWebElementWithId;
using chrome_test_util::WebViewMatcher; using chrome_test_util::WebViewMatcher;
namespace { namespace {
...@@ -37,14 +41,10 @@ const std::string kFormElementSubmit = "submit"; ...@@ -37,14 +41,10 @@ const std::string kFormElementSubmit = "submit";
// If an element is focused in the webview, returns its ID. Returns an empty // If an element is focused in the webview, returns its ID. Returns an empty
// NSString otherwise. // NSString otherwise.
NSString* GetFocusedElementID() { NSString* GetFocusedElementID() {
NSString* js = NSString* javaScript = @"(function() {"
@"(function() {" " return document.activeElement.id;"
" return document.activeElement.id;" "})();";
"})();"; return [ChromeEarlGrey executeJavaScript:javaScript];
NSError* error = nil;
NSString* result = chrome_test_util::ExecuteJavaScript(js, &error);
GREYAssertNil(error, @"Unexpected error when executing JavaScript.");
return result;
} }
// Verifies that |elementId| is the selected element in the web page. // Verifies that |elementId| is the selected element in the web page.
...@@ -57,16 +57,13 @@ void AssertElementIsFocused(const std::string& element_id) { ...@@ -57,16 +57,13 @@ void AssertElementIsFocused(const std::string& element_id) {
ConditionBlock condition = ^{ ConditionBlock condition = ^{
return base::SysNSStringToUTF8(GetFocusedElementID()) == element_id; return base::SysNSStringToUTF8(GetFocusedElementID()) == element_id;
}; };
GREYAssert(base::test::ios::WaitUntilConditionOrTimeout(10, condition), GREYAssert(WaitUntilConditionOrTimeout(10, condition), description);
description);
} }
// Helper to tap a web element. // Helper to tap a web element.
void TapOnWebElementWithID(const std::string& elementID) { void TapOnWebElementWithID(const std::string& elementID) {
[[EarlGrey selectElementWithMatcher:WebViewMatcher()] [[EarlGrey selectElementWithMatcher:WebViewMatcher()]
performAction:web::WebViewTapElement( performAction:TapWebElementWithId(elementID)];
chrome_test_util::GetCurrentWebState(),
[ElementSelector selectorWithElementID:elementID])];
} }
} // namespace } // namespace
...@@ -75,14 +72,7 @@ void TapOnWebElementWithID(const std::string& elementID) { ...@@ -75,14 +72,7 @@ void TapOnWebElementWithID(const std::string& elementID) {
@interface KeyboardObserverTestCase : ChromeTestCase @interface KeyboardObserverTestCase : ChromeTestCase
// Observer to be tested. // Observer to be tested.
@property(nonatomic, strong) KeyboardObserverHelper* keyboardObserver; @property(nonatomic, strong) KeyboardObserverHelper* keyboardObserverHelper;
// Token to register a NSNotificationCenter observer.
@property(nonatomic, strong) id<NSObject> notificationToken;
// Delegate mock to confirm the observer callbacks.
@property(nonatomic, strong)
OCMockObject<KeyboardObserverHelperConsumer>* keyboardObserverDelegateMock;
@end @end
...@@ -90,100 +80,43 @@ void TapOnWebElementWithID(const std::string& elementID) { ...@@ -90,100 +80,43 @@ void TapOnWebElementWithID(const std::string& elementID) {
- (void)setUp { - (void)setUp {
[super setUp]; [super setUp];
self.keyboardObserver = [[KeyboardObserverHelper alloc] init]; self.keyboardObserverHelper =
self.keyboardObserverDelegateMock = [KeyboardObserverHelperAppInterface appSharedInstance];
OCMProtocolMock(@protocol(KeyboardObserverHelperConsumer));
self.keyboardObserver.consumer = self.keyboardObserverDelegateMock; GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
const GURL URL = self.testServer->GetURL("/multi_field_form.html");
web::test::SetUpFileBasedHttpServer();
GURL URL = web::test::HttpServer::MakeUrl(
"http://ios/testing/data/http_server_files/multi_field_form.html");
[ChromeEarlGrey loadURL:URL]; [ChromeEarlGrey loadURL:URL];
[ChromeEarlGrey waitForWebStateContainingText:"hello!"]; [ChromeEarlGrey waitForWebStateContainingText:"hello!"];
} }
- (void)tearDown { - (void)tearDown {
self.notificationToken = nil; self.keyboardObserverHelper = nil;
self.keyboardObserverDelegateMock = nil;
self.keyboardObserver = nil;
[super tearDown]; [super tearDown];
} }
// Tests the observer correctly identifies when the keyboard stays on screen.
- (void)testKeyboardDidStayOnScreen {
if (@available(iOS 13, *)) {
// On iOS 13 keyboardDidStayOnScreen is not called. This makes the
// workaround not needed anymore.
return;
}
// Opening the keyboard from a webview blocks EarlGrey's synchronization.
ScopedSynchronizationDisabler disabler;
// Brings up the keyboard by tapping on one of the form's field.
TapOnWebElementWithID(kFormElementID1);
// Wait for keyboard to finish animating.
__block BOOL keyboardDidAppear = NO;
self.notificationToken = [[NSNotificationCenter defaultCenter]
addObserverForName:UIKeyboardDidShowNotification
object:nil
queue:nil
usingBlock:^(NSNotification* note) {
keyboardDidAppear = YES;
}];
ConditionBlock condition = ^{
return keyboardDidAppear;
};
using base::test::ios::WaitUntilConditionOrTimeout;
using base::test::ios::kWaitForUIElementTimeout;
GREYAssert(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, condition),
@"Wait for keyboard did show notification");
// Verifies that the taped element is focused.
AssertElementIsFocused(kFormElementID1);
// Create a new callback expectation.
OCMExpect([self.keyboardObserverDelegateMock keyboardDidStayOnScreen]);
// Reset our keyboard boolean.
keyboardDidAppear = NO;
// Tap the second field.
TapOnWebElementWithID(kFormElementID2);
// Wait for keyboard to finish animating.
GREYAssert(WaitUntilConditionOrTimeout(kWaitForUIElementTimeout, condition),
@"Wait for keyboard did show notification");
// Verifies that the taped element is focused.
AssertElementIsFocused(kFormElementID2);
// Verify the delegate call was made.
[self.keyboardObserverDelegateMock verify];
}
// Tests that when the keyboard actually dismiss the right callback is done. // Tests that when the keyboard actually dismiss the right callback is done.
// TODO(crbug.com/914374): Address flakiness and reenable. - (void)testKeyboardHideState {
- (void)DISABLED_testKeyboardDidHide {
// Opening the keyboard from a webview blocks EarlGrey's synchronization. // Opening the keyboard from a webview blocks EarlGrey's synchronization.
ScopedSynchronizationDisabler disabler; ScopedSynchronizationDisabler disabler;
// Brings up the keyboard by tapping on one of the form's field. // Brings up the keyboard by tapping on one of the form's field.
TapOnWebElementWithID(kFormElementID1); TapOnWebElementWithID(kFormElementID1);
// Verifies that the taped element is focused. // Verifies that the taped element is focused.
AssertElementIsFocused(kFormElementID1); AssertElementIsFocused(kFormElementID1);
// Create the callback expectation. // Verify the visible state.
KeyboardState keyboardState = {NO, NO, NO, NO, NO}; KeyboardObserverHelper* observer = self.keyboardObserverHelper;
OCMExpect([self.keyboardObserverDelegateMock GREYAssertTrue(observer.keyboardState.isVisible,
keyboardWillChangeToState:keyboardState]); @"Keyboard should be visible.");
// Tap the "Submit" button, and let the run loop spin. // Tap the "Submit" button, and let the run loop spin.
TapOnWebElementWithID(kFormElementSubmit); TapOnWebElementWithID(kFormElementSubmit);
base::test::ios::SpinRunLoopWithMinDelay(base::TimeDelta::FromSeconds(1)); base::test::ios::SpinRunLoopWithMinDelay(base::TimeDelta::FromSeconds(1));
// Verify the delegate call was made. // Verify the state changed.
[self.keyboardObserverDelegateMock verify]; GREYAssertFalse(observer.keyboardState.isVisible,
@"Keyboard shouldn't be visible.");
} }
@end @end
...@@ -214,3 +214,56 @@ bundle_data("terms_resources") { ...@@ -214,3 +214,56 @@ bundle_data("terms_resources") {
"{{bundle_resources_dir}}/{{source_file_part}}", "{{bundle_resources_dir}}/{{source_file_part}}",
] ]
} }
source_set("test_support") {
defines = [ "CHROME_EARL_GREY_1" ]
configs += [ "//build/config/compiler:enable_arc" ]
testonly = true
sources = [
"keyboard_observer_helper_app_interface.h",
"keyboard_observer_helper_app_interface.mm",
]
deps = [
":util",
"//base",
"//base/test:test_support",
"//ios/chrome/test/app:test_support",
"//ios/testing/earl_grey:earl_grey_support",
]
}
source_set("eg_app_support+eg2") {
defines = [ "CHROME_EARL_GREY_2" ]
configs += [
"//build/config/compiler:enable_arc",
"//build/config/ios:xctest_config",
]
testonly = true
sources = [
"keyboard_observer_helper_app_interface.h",
"keyboard_observer_helper_app_interface.mm",
]
deps = [
":util",
"//base",
"//base/test:test_support",
"//ios/chrome/test/app:test_support",
]
}
source_set("eg_test_support+eg2") {
defines = [ "CHROME_EARL_GREY_2" ]
configs += [
"//build/config/compiler:enable_arc",
"//build/config/ios:xctest_config",
]
testonly = true
sources = [
"keyboard_observer_helper_app_interface.h",
]
deps = [
":util",
"//ios/testing/earl_grey:eg_test_support+eg2",
"//ios/third_party/earl_grey2:test_lib",
]
}
// Copyright 2019 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.
#ifndef IOS_CHROME_BROWSER_UI_UTIL_KEYBOARD_OBSERVER_HELPER_APP_INTERFACE_H_
#define IOS_CHROME_BROWSER_UI_UTIL_KEYBOARD_OBSERVER_HELPER_APP_INTERFACE_H_
#import <Foundation/Foundation.h>
@class KeyboardObserverHelper;
// Utility to interact with a KeyboardObserverInstance on Earl Grey 2 tests.
@interface KeyboardObserverHelperAppInterface : NSObject
// Returns a shared instance of the observer.
+ (KeyboardObserverHelper*)appSharedInstance;
@end
#endif // IOS_CHROME_BROWSER_UI_UTIL_KEYBOARD_OBSERVER_HELPER_APP_INTERFACE_H_
// Copyright 2019 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/browser/ui/util/keyboard_observer_helper_app_interface.h"
#import "ios/chrome/browser/ui/util/keyboard_observer_helper.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
@implementation KeyboardObserverHelperAppInterface
+ (KeyboardObserverHelper*)appSharedInstance {
static KeyboardObserverHelper* sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[KeyboardObserverHelper alloc] init];
});
return sharedInstance;
}
@end
...@@ -404,6 +404,7 @@ source_set("eg_app_support+eg2") { ...@@ -404,6 +404,7 @@ source_set("eg_app_support+eg2") {
"//ios/chrome/browser/ui/toolbar/keyboard_assist", "//ios/chrome/browser/ui/toolbar/keyboard_assist",
"//ios/chrome/browser/ui/toolbar/public", "//ios/chrome/browser/ui/toolbar/public",
"//ios/chrome/browser/ui/util", "//ios/chrome/browser/ui/util",
"//ios/chrome/browser/ui/util:eg_app_support+eg2",
"//ios/chrome/browser/web:tab_id_tab_helper", "//ios/chrome/browser/web:tab_id_tab_helper",
"//ios/chrome/test/app:test_support", "//ios/chrome/test/app:test_support",
"//ios/chrome/test/base", "//ios/chrome/test/base",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment