blob: 3f4d15d8db978b6ad76cea4f0a401b236d43dded [file] [log] [blame]
// 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_earl_grey.h"
#import <Foundation/Foundation.h>
#import <WebKit/WebKit.h>
#include "base/format_macros.h"
#include "base/mac/foundation_util.h"
#include "base/strings/sys_string_conversions.h"
#import "base/test/ios/wait_util.h"
#include "components/strings/grit/components_strings.h"
#import "ios/chrome/browser/ui/static_content/static_html_view_controller.h"
#import "ios/chrome/test/app/bookmarks_test_util.h"
#import "ios/chrome/test/app/chrome_test_util.h"
#import "ios/chrome/test/app/history_test_util.h"
#include "ios/chrome/test/app/navigation_test_util.h"
#import "ios/chrome/test/app/static_html_view_test_util.h"
#import "ios/chrome/test/app/tab_test_util.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
#import "ios/web/public/test/earl_grey/js_test_util.h"
#include "ios/web/public/test/element_selector.h"
#import "ios/web/public/test/web_view_content_test_util.h"
#import "ios/web/public/test/web_view_interaction_test_util.h"
#import "ios/web/public/web_state/js/crw_js_injection_receiver.h"
#import "ios/web/public/web_state/web_state.h"
#include "ui/base/l10n/l10n_util.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace chrome_test_util {
id ExecuteJavaScript(NSString* javascript,
NSError* __autoreleasing* out_error) {
__block bool did_complete = false;
__block id result = nil;
__block NSError* temp_error = nil;
CRWJSInjectionReceiver* evaluator =
chrome_test_util::GetCurrentWebState()->GetJSInjectionReceiver();
[evaluator executeJavaScript:javascript
completionHandler:^(id value, NSError* error) {
did_complete = true;
result = [value copy];
temp_error = [error copy];
}];
// Wait for completion.
GREYCondition* condition = [GREYCondition
conditionWithName:@"Wait for JavaScript execution to complete."
block:^BOOL {
return did_complete;
}];
[condition waitWithTimeout:base::test::ios::kWaitForJSCompletionTimeout];
if (!did_complete)
return nil;
if (out_error) {
NSError* __autoreleasing auto_released_error = temp_error;
*out_error = auto_released_error;
}
return result;
}
} // namespace chrome_test_util
@implementation ChromeEarlGrey
#pragma mark - History Utilities
+ (void)clearBrowsingHistory {
GREYAssertTrue(chrome_test_util::ClearBrowsingHistory(),
@"Clearing Browsing History timed out");
// After clearing browsing history via code, wait for the UI to be done
// with any updates. This includes icons from the new tab page being removed.
[[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
}
#pragma mark - Cookie Utilities
+ (NSDictionary*)cookies {
NSString* const kGetCookiesScript =
@"document.cookie ? document.cookie.split(/;\\s*/) : [];";
NSError* error = nil;
id result = chrome_test_util::ExecuteJavaScript(kGetCookiesScript, &error);
GREYAssertTrue(result && !error, @"Failed to get cookies.");
NSArray* nameValuePairs = base::mac::ObjCCastStrict<NSArray>(result);
NSMutableDictionary* cookies = [NSMutableDictionary dictionary];
for (NSString* nameValuePair in nameValuePairs) {
NSArray* cookieNameValue = [nameValuePair componentsSeparatedByString:@"="];
GREYAssertEqual(2U, cookieNameValue.count, @"Cookie has invalid format.");
NSString* cookieName = cookieNameValue[0];
NSString* cookieValue = cookieNameValue[1];
cookies[cookieName] = cookieValue;
}
return cookies;
}
#pragma mark - Navigation Utilities
+ (void)loadURL:(const GURL&)URL {
chrome_test_util::LoadUrl(URL);
[ChromeEarlGrey waitForPageToFinishLoading];
web::WebState* webState = chrome_test_util::GetCurrentWebState();
if (webState->ContentIsHTML())
web::WaitUntilWindowIdInjected(webState);
}
+ (void)reload {
[chrome_test_util::BrowserCommandDispatcherForMainBVC() reload];
[ChromeEarlGrey waitForPageToFinishLoading];
}
+ (void)goBack {
[chrome_test_util::BrowserCommandDispatcherForMainBVC() goBack];
[ChromeEarlGrey waitForPageToFinishLoading];
}
+ (void)goForward {
[chrome_test_util::BrowserCommandDispatcherForMainBVC() goForward];
[ChromeEarlGrey waitForPageToFinishLoading];
}
+ (void)openNewTab {
chrome_test_util::OpenNewTab();
[ChromeEarlGrey waitForPageToFinishLoading];
[[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
}
+ (void)openNewIncognitoTab {
chrome_test_util::OpenNewIncognitoTab();
[ChromeEarlGrey waitForPageToFinishLoading];
[[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
}
+ (void)closeAllTabsInCurrentMode {
chrome_test_util::CloseAllTabsInCurrentMode();
[[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
}
+ (void)closeAllIncognitoTabs {
GREYAssert(chrome_test_util::CloseAllIncognitoTabs(), @"Tabs did not close");
[[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
}
+ (void)closeCurrentTab {
chrome_test_util::CloseCurrentTab();
[[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
}
+ (void)waitForPageToFinishLoading {
GREYAssert(chrome_test_util::WaitForPageToFinishLoading(),
@"Page did not complete loading.");
}
+ (void)tapWebViewElementWithID:(NSString*)elementID {
BOOL success =
web::test::TapWebViewElementWithId(chrome_test_util::GetCurrentWebState(),
base::SysNSStringToUTF8(elementID));
GREYAssertTrue(success, @"Failed to tap web view element with ID: %@",
elementID);
}
+ (void)waitForErrorPage {
NSString* const kErrorPageText =
l10n_util::GetNSString(IDS_ERRORPAGES_HEADING_NOT_AVAILABLE);
[self waitForStaticHTMLViewContainingText:kErrorPageText];
}
+ (void)waitForStaticHTMLViewContainingText:(NSString*)text {
GREYCondition* condition = [GREYCondition
conditionWithName:@"Wait for static HTML text."
block:^BOOL {
return chrome_test_util::StaticHtmlViewContainingText(
chrome_test_util::GetCurrentWebState(),
base::SysNSStringToUTF8(text));
}];
GREYAssert(
[condition waitWithTimeout:base::test::ios::kWaitForUIElementTimeout],
@"Failed to find static html view containing %@", text);
}
+ (void)waitForStaticHTMLViewNotContainingText:(NSString*)text {
GREYCondition* condition = [GREYCondition
conditionWithName:@"Wait for absence of static HTML text."
block:^BOOL {
return !chrome_test_util::StaticHtmlViewContainingText(
chrome_test_util::GetCurrentWebState(),
base::SysNSStringToUTF8(text));
}];
GREYAssert(
[condition waitWithTimeout:base::test::ios::kWaitForUIElementTimeout],
@"Failed, there was a static html view containing %@", text);
}
+ (void)waitForWebViewContainingText:(std::string)text {
GREYCondition* condition = [GREYCondition
conditionWithName:@"Wait for web view containing text"
block:^BOOL {
return web::test::IsWebViewContainingText(
chrome_test_util::GetCurrentWebState(), text);
}];
GREYAssert(
[condition waitWithTimeout:base::test::ios::kWaitForUIElementTimeout],
@"Failed waiting for web view containing %s", text.c_str());
}
+ (void)waitForWebViewContainingElement:
(const web::test::ElementSelector)selector {
GREYCondition* condition = [GREYCondition
conditionWithName:@"Wait for web view containing Element"
block:^BOOL {
return web::test::IsWebViewContainingElement(
chrome_test_util::GetCurrentWebState(), selector);
}];
GREYAssert(
[condition waitWithTimeout:base::test::ios::kWaitForUIElementTimeout],
@"Failed waiting for web view containing element %s",
selector.GetSelectorDescription().c_str());
}
+ (void)waitForWebViewNotContainingText:(std::string)text {
GREYCondition* condition = [GREYCondition
conditionWithName:@"Wait for web view not containing text"
block:^BOOL {
return !web::test::IsWebViewContainingText(
chrome_test_util::GetCurrentWebState(), text);
}];
GREYAssert(
[condition waitWithTimeout:base::test::ios::kWaitForUIElementTimeout],
@"Failed waiting for web view not containing %s", text.c_str());
}
+ (void)waitForMainTabCount:(NSUInteger)count {
// Allow the UI to become idle, in case any tabs are being opened or closed.
[[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
GREYCondition* condition = [GREYCondition
conditionWithName:@"Wait for main tab count"
block:^BOOL {
return chrome_test_util::GetMainTabCount() == count;
}];
GREYAssert(
[condition waitWithTimeout:base::test::ios::kWaitForUIElementTimeout],
@"Failed waiting for main tab count to become %" PRIuNS, count);
}
+ (void)waitForIncognitoTabCount:(NSUInteger)count {
// Allow the UI to become idle, in case any tabs are being opened or closed.
[[GREYUIThreadExecutor sharedInstance] drainUntilIdle];
GREYCondition* condition = [GREYCondition
conditionWithName:@"Wait for incognito tab count"
block:^BOOL {
return chrome_test_util::GetIncognitoTabCount() == count;
}];
GREYAssert(
[condition waitWithTimeout:base::test::ios::kWaitForUIElementTimeout],
@"Failed waiting for incognito tab count to become %" PRIuNS, count);
}
+ (void)waitForWebViewContainingBlockedImageElementWithID:(std::string)imageID {
GREYAssert(web::test::WaitForWebViewContainingImage(
imageID, chrome_test_util::GetCurrentWebState(),
web::test::IMAGE_STATE_BLOCKED),
@"Failed waiting for web view blocked image %s", imageID.c_str());
}
+ (void)waitForWebViewContainingLoadedImageElementWithID:(std::string)imageID {
GREYAssert(web::test::WaitForWebViewContainingImage(
imageID, chrome_test_util::GetCurrentWebState(),
web::test::IMAGE_STATE_LOADED),
@"Failed waiting for web view loaded image %s", imageID.c_str());
}
+ (void)waitForBookmarksToFinishLoading {
GREYAssert(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForUIElementTimeout,
^{
return chrome_test_util::BookmarksLoaded();
}),
@"Bookmark model did not load");
}
+ (void)waitForElementWithMatcherSufficientlyVisible:(id<GREYMatcher>)matcher {
GREYCondition* condition = [GREYCondition
conditionWithName:@"Wait for element with matcher sufficiently visible"
block:^BOOL {
NSError* error = nil;
[[EarlGrey selectElementWithMatcher:matcher]
assertWithMatcher:grey_sufficientlyVisible()
error:&error];
return error == nil;
}];
GREYAssert(
[condition waitWithTimeout:base::test::ios::kWaitForUIElementTimeout],
@"Failed waiting for element with matcher %@ to become visible", matcher);
}
@end