Skip to content

Commit

Permalink
[iOS][MF][EG2] Migrate keyboard observer test
Browse files Browse the repository at this point in the history
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: Javier Ernesto Flores Robles <javierrobles@chromium.org>
Reviewed-by: Stepan Khapugin <stkhapugin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#709939}
  • Loading branch information
Javier Ernesto Flores Robles authored and Commit Bot committed Oct 28, 2019
1 parent c117648 commit 959cddb
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 105 deletions.
6 changes: 5 additions & 1 deletion ios/chrome/browser/ui/autofill/manual_fill/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ source_set("eg_tests") {
"//ios/chrome/browser/ui/settings/autofill:feature_flags",
"//ios/chrome/browser/ui/settings/password",
"//ios/chrome/browser/ui/util",
"//ios/chrome/browser/ui/util:test_support",
"//ios/chrome/test:eg_test_support",
"//ios/chrome/test/app:test_support",
"//ios/chrome/test/earl_grey:test_support",
Expand All @@ -224,7 +225,6 @@ source_set("eg_tests") {
"//ios/web:earl_grey_test_support",
"//ios/web/public/test:element_selector",
"//ios/web/public/test/http_server",
"//third_party/ocmock",
]
}

Expand All @@ -240,6 +240,7 @@ source_set("eg2_tests") {
"card_view_controller_egtest.mm",
"fallback_coordinator_egtest.mm",
"fallback_view_controller_egtest.mm",
"keyboard_observer_egtest.mm",
"password_view_controller_egtest.mm",
]
deps = [
Expand All @@ -248,6 +249,9 @@ source_set("eg2_tests") {
"//ios/chrome/app/strings:ios_strings_grit",
"//ios/chrome/browser/ui/autofill:eg_test_support+eg2",
"//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/testing/earl_grey:eg_test_support+eg2",
"//ios/third_party/earl_grey2:test_lib",
Expand Down
141 changes: 37 additions & 104 deletions ios/chrome/browser/ui/autofill/manual_fill/keyboard_observer_egtest.mm
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,34 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import <EarlGrey/EarlGrey.h>
#import <EarlGrey/GREYKeyboard.h>

#include "base/mac/foundation_util.h"
#include "base/strings/sys_string_conversions.h"
#import "base/test/ios/wait_util.h"
#import "ios/chrome/browser/ui/util/keyboard_observer_helper.h"
#import "ios/chrome/test/app/chrome_test_util.h"
#import "ios/chrome/test/app/tab_test_util.h"
#import "ios/chrome/browser/ui/util/keyboard_observer_helper_app_interface.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_matchers.h"
#import "ios/chrome/test/earl_grey/chrome_test_case.h"
#import "ios/chrome/test/scoped_eg_synchronization_disabler.h"
#import "ios/web/public/test/earl_grey/web_view_actions.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"
#import "ios/testing/earl_grey/earl_grey_test.h"

#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#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;

namespace {
Expand All @@ -37,14 +41,10 @@
// If an element is focused in the webview, returns its ID. Returns an empty
// NSString otherwise.
NSString* GetFocusedElementID() {
NSString* js =
@"(function() {"
" return document.activeElement.id;"
"})();";
NSError* error = nil;
NSString* result = chrome_test_util::ExecuteJavaScript(js, &error);
GREYAssertNil(error, @"Unexpected error when executing JavaScript.");
return result;
NSString* javaScript = @"(function() {"
" return document.activeElement.id;"
"})();";
return [ChromeEarlGrey executeJavaScript:javaScript];
}

// Verifies that |elementId| is the selected element in the web page.
Expand All @@ -57,16 +57,13 @@ void AssertElementIsFocused(const std::string& element_id) {
ConditionBlock condition = ^{
return base::SysNSStringToUTF8(GetFocusedElementID()) == element_id;
};
GREYAssert(base::test::ios::WaitUntilConditionOrTimeout(10, condition),
description);
GREYAssert(WaitUntilConditionOrTimeout(10, condition), description);
}

// Helper to tap a web element.
void TapOnWebElementWithID(const std::string& elementID) {
[[EarlGrey selectElementWithMatcher:WebViewMatcher()]
performAction:web::WebViewTapElement(
chrome_test_util::GetCurrentWebState(),
[ElementSelector selectorWithElementID:elementID])];
performAction:TapWebElementWithId(elementID)];
}

} // namespace
Expand All @@ -75,115 +72,51 @@ void TapOnWebElementWithID(const std::string& elementID) {
@interface KeyboardObserverTestCase : ChromeTestCase

// Observer to be tested.
@property(nonatomic, strong) KeyboardObserverHelper* keyboardObserver;

// 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;
@property(nonatomic, strong) KeyboardObserverHelper* keyboardObserverHelper;

@end

@implementation KeyboardObserverTestCase

- (void)setUp {
[super setUp];
self.keyboardObserver = [[KeyboardObserverHelper alloc] init];
self.keyboardObserverDelegateMock =
OCMProtocolMock(@protocol(KeyboardObserverHelperConsumer));
self.keyboardObserver.consumer = self.keyboardObserverDelegateMock;

web::test::SetUpFileBasedHttpServer();
GURL URL = web::test::HttpServer::MakeUrl(
"http://ios/testing/data/http_server_files/multi_field_form.html");
self.keyboardObserverHelper =
[KeyboardObserverHelperAppInterface appSharedInstance];

GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
const GURL URL = self.testServer->GetURL("/multi_field_form.html");
[ChromeEarlGrey loadURL:URL];
[ChromeEarlGrey waitForWebStateContainingText:"hello!"];
}

- (void)tearDown {
self.notificationToken = nil;
self.keyboardObserverDelegateMock = nil;
self.keyboardObserver = nil;
self.keyboardObserverHelper = nil;
[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.
// TODO(crbug.com/914374): Address flakiness and reenable.
- (void)DISABLED_testKeyboardDidHide {
- (void)testKeyboardHideState {
// 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);

// Verifies that the taped element is focused.
AssertElementIsFocused(kFormElementID1);

// Create the callback expectation.
KeyboardState keyboardState = {NO, NO, NO, NO, NO};
OCMExpect([self.keyboardObserverDelegateMock
keyboardWillChangeToState:keyboardState]);
// Verify the visible state.
KeyboardObserverHelper* observer = self.keyboardObserverHelper;
GREYAssertTrue(observer.keyboardState.isVisible,
@"Keyboard should be visible.");

// Tap the "Submit" button, and let the run loop spin.
TapOnWebElementWithID(kFormElementSubmit);
base::test::ios::SpinRunLoopWithMinDelay(base::TimeDelta::FromSeconds(1));

// Verify the delegate call was made.
[self.keyboardObserverDelegateMock verify];
// Verify the state changed.
GREYAssertFalse(observer.keyboardState.isVisible,
@"Keyboard shouldn't be visible.");
}

@end
53 changes: 53 additions & 0 deletions ios/chrome/browser/ui/util/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -214,3 +214,56 @@ bundle_data("terms_resources") {
"{{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",
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// 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_
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// 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
1 change: 1 addition & 0 deletions ios/chrome/test/earl_grey/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,7 @@ source_set("eg_app_support+eg2") {
"//ios/chrome/browser/ui/toolbar/keyboard_assist",
"//ios/chrome/browser/ui/toolbar/public",
"//ios/chrome/browser/ui/util",
"//ios/chrome/browser/ui/util:eg_app_support+eg2",
"//ios/chrome/browser/web:tab_id_tab_helper",
"//ios/chrome/test/app:test_support",
"//ios/chrome/test/base",
Expand Down

0 comments on commit 959cddb

Please sign in to comment.