| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #import "ios/web/public/test/earl_grey/web_view_matchers.h" | 5 #import "ios/web/public/test/earl_grey/web_view_matchers.h" |
| 6 | 6 |
| 7 #import <UIKit/UIKit.h> | 7 #import <UIKit/UIKit.h> |
| 8 #import <WebKit/WebKit.h> | 8 #import <WebKit/WebKit.h> |
| 9 | 9 |
| 10 #import "base/mac/bind_objc_block.h" | 10 #import "base/mac/bind_objc_block.h" |
| 11 #import "base/mac/scoped_nsobject.h" | |
| 12 #include "base/strings/stringprintf.h" | 11 #include "base/strings/stringprintf.h" |
| 13 #include "base/strings/sys_string_conversions.h" | 12 #include "base/strings/sys_string_conversions.h" |
| 14 #include "base/strings/utf_string_conversions.h" | 13 #include "base/strings/utf_string_conversions.h" |
| 15 #import "base/test/ios/wait_util.h" | 14 #import "base/test/ios/wait_util.h" |
| 16 #include "base/values.h" | 15 #include "base/values.h" |
| 17 #import "ios/testing/wait_util.h" | 16 #import "ios/testing/wait_util.h" |
| 18 #import "ios/web/interstitials/web_interstitial_impl.h" | 17 #import "ios/web/interstitials/web_interstitial_impl.h" |
| 19 #import "ios/web/public/test/earl_grey/js_test_util.h" | 18 #import "ios/web/public/test/earl_grey/js_test_util.h" |
| 20 #import "ios/web/public/test/web_view_interaction_test_util.h" | 19 #import "ios/web/public/test/web_view_interaction_test_util.h" |
| 21 #import "net/base/mac/url_conversions.h" | 20 #import "net/base/mac/url_conversions.h" |
| 22 | 21 |
| 22 #if !defined(__has_feature) || !__has_feature(objc_arc) |
| 23 #error "This file requires ARC support." |
| 24 #endif |
| 25 |
| 23 using testing::kWaitForDownloadTimeout; | 26 using testing::kWaitForDownloadTimeout; |
| 24 using testing::WaitUntilConditionOrTimeout; | 27 using testing::WaitUntilConditionOrTimeout; |
| 25 | 28 |
| 26 // A helper delegate class that allows downloading responses with invalid | 29 // A helper delegate class that allows downloading responses with invalid |
| 27 // SSL certs. | 30 // SSL certs. |
| 28 @interface TestURLSessionDelegate : NSObject<NSURLSessionDelegate> | 31 @interface TestURLSessionDelegate : NSObject<NSURLSessionDelegate> |
| 29 @end | 32 @end |
| 30 | 33 |
| 31 @implementation TestURLSessionDelegate | 34 @implementation TestURLSessionDelegate |
| 32 | 35 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 52 }; | 55 }; |
| 53 | 56 |
| 54 // Script that returns document.body as a string. | 57 // Script that returns document.body as a string. |
| 55 char kGetDocumentBodyJavaScript[] = | 58 char kGetDocumentBodyJavaScript[] = |
| 56 "document.body ? document.body.textContent : null"; | 59 "document.body ? document.body.textContent : null"; |
| 57 // Script that tests presence of css selector. | 60 // Script that tests presence of css selector. |
| 58 char kTestCssSelectorJavaScriptTemplate[] = "!!document.querySelector(\"%s\");"; | 61 char kTestCssSelectorJavaScriptTemplate[] = "!!document.querySelector(\"%s\");"; |
| 59 | 62 |
| 60 // Fetches the image from |image_url|. | 63 // Fetches the image from |image_url|. |
| 61 UIImage* LoadImage(const GURL& image_url) { | 64 UIImage* LoadImage(const GURL& image_url) { |
| 62 __block base::scoped_nsobject<UIImage> image; | 65 __block UIImage* image; |
| 63 __block base::scoped_nsobject<NSError> error; | 66 __block NSError* error; |
| 64 TestURLSessionDelegate* session_delegate = | 67 TestURLSessionDelegate* session_delegate = |
| 65 [[TestURLSessionDelegate alloc] init]; | 68 [[TestURLSessionDelegate alloc] init]; |
| 66 NSURLSessionConfiguration* session_config = | 69 NSURLSessionConfiguration* session_config = |
| 67 [NSURLSessionConfiguration defaultSessionConfiguration]; | 70 [NSURLSessionConfiguration defaultSessionConfiguration]; |
| 68 NSURLSession* session = | 71 NSURLSession* session = |
| 69 [NSURLSession sessionWithConfiguration:session_config | 72 [NSURLSession sessionWithConfiguration:session_config |
| 70 delegate:session_delegate | 73 delegate:session_delegate |
| 71 delegateQueue:nil]; | 74 delegateQueue:nil]; |
| 72 id completion_handler = ^(NSData* data, NSURLResponse*, NSError* task_error) { | 75 id completion_handler = ^(NSData* data, NSURLResponse*, NSError* task_error) { |
| 73 if (task_error) { | 76 error = task_error; |
| 74 error.reset([task_error retain]); | 77 image = [[UIImage alloc] initWithData:data]; |
| 75 } else { | |
| 76 image.reset([[UIImage alloc] initWithData:data]); | |
| 77 } | |
| 78 [session_delegate autorelease]; | |
| 79 }; | 78 }; |
| 80 | 79 |
| 81 NSURLSessionDataTask* task = | 80 NSURLSessionDataTask* task = |
| 82 [session dataTaskWithURL:net::NSURLWithGURL(image_url) | 81 [session dataTaskWithURL:net::NSURLWithGURL(image_url) |
| 83 completionHandler:completion_handler]; | 82 completionHandler:completion_handler]; |
| 84 [task resume]; | 83 [task resume]; |
| 85 | 84 |
| 86 bool image_loaded = WaitUntilConditionOrTimeout(kWaitForDownloadTimeout, ^{ | 85 bool image_loaded = WaitUntilConditionOrTimeout(kWaitForDownloadTimeout, ^{ |
| 87 return image || error; | 86 return image || error; |
| 88 }); | 87 }); |
| 89 GREYAssert(image_loaded, @"Failed to download image"); | 88 GREYAssert(image_loaded, @"Failed to download image"); |
| 90 | 89 |
| 91 return [[image retain] autorelease]; | 90 return image; |
| 92 } | 91 } |
| 93 | 92 |
| 94 // Helper function for matching web views containing or not containing |text|, | 93 // Helper function for matching web views containing or not containing |text|, |
| 95 // depending on the value of |should_contain_text|. | 94 // depending on the value of |should_contain_text|. |
| 96 id<GREYMatcher> WebViewWithText(std::string text, | 95 id<GREYMatcher> WebViewWithText(std::string text, |
| 97 web::WebState* web_state, | 96 web::WebState* web_state, |
| 98 bool should_contain_text) { | 97 bool should_contain_text) { |
| 99 MatchesBlock matches = ^BOOL(WKWebView*) { | 98 MatchesBlock matches = ^BOOL(WKWebView*) { |
| 100 return WaitUntilConditionOrTimeout(testing::kWaitForUIElementTimeout, ^{ | 99 return WaitUntilConditionOrTimeout(testing::kWaitForUIElementTimeout, ^{ |
| 101 std::unique_ptr<base::Value> value = | 100 std::unique_ptr<base::Value> value = |
| 102 web::test::ExecuteJavaScript(web_state, kGetDocumentBodyJavaScript); | 101 web::test::ExecuteJavaScript(web_state, kGetDocumentBodyJavaScript); |
| 103 std::string body; | 102 std::string body; |
| 104 if (value && value->GetAsString(&body)) { | 103 if (value && value->GetAsString(&body)) { |
| 105 BOOL contains_text = body.find(text) != std::string::npos; | 104 BOOL contains_text = body.find(text) != std::string::npos; |
| 106 return contains_text == should_contain_text; | 105 return contains_text == should_contain_text; |
| 107 } | 106 } |
| 108 return false; | 107 return false; |
| 109 }); | 108 }); |
| 110 }; | 109 }; |
| 111 | 110 |
| 112 DescribeToBlock describe = ^(id<GREYDescription> description) { | 111 DescribeToBlock describe = ^(id<GREYDescription> description) { |
| 113 [description appendText:should_contain_text ? @"web view containing " | 112 [description appendText:should_contain_text ? @"web view containing " |
| 114 : @"web view not containing "]; | 113 : @"web view not containing "]; |
| 115 [description appendText:base::SysUTF8ToNSString(text)]; | 114 [description appendText:base::SysUTF8ToNSString(text)]; |
| 116 }; | 115 }; |
| 117 | 116 |
| 118 return grey_allOf(WebViewInWebState(web_state), | 117 return grey_allOf( |
| 119 [[[GREYElementMatcherBlock alloc] | 118 WebViewInWebState(web_state), |
| 120 initWithMatchesBlock:matches | 119 [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches |
| 121 descriptionBlock:describe] autorelease], | 120 descriptionBlock:describe], |
| 122 nil); | 121 nil); |
| 123 } | 122 } |
| 124 | 123 |
| 125 // Matcher for WKWebView containing loaded or blocked image with |image_id|. | 124 // Matcher for WKWebView containing loaded or blocked image with |image_id|. |
| 126 // Pass IMAGE_STATE_LOADED |image_state| to match fully loaded image and | 125 // Pass IMAGE_STATE_LOADED |image_state| to match fully loaded image and |
| 127 // IMAGE_STATE_BLOCKED to match fully blocked image. | 126 // IMAGE_STATE_BLOCKED to match fully blocked image. |
| 128 id<GREYMatcher> WebViewContainingImage(std::string image_id, | 127 id<GREYMatcher> WebViewContainingImage(std::string image_id, |
| 129 web::WebState* web_state, | 128 web::WebState* web_state, |
| 130 ImageState image_state) { | 129 ImageState image_state) { |
| 131 std::string get_url_script = | 130 std::string get_url_script = |
| 132 base::StringPrintf("document.getElementById('%s').src", image_id.c_str()); | 131 base::StringPrintf("document.getElementById('%s').src", image_id.c_str()); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 184 [description appendText:@"web view blocked resource with id "]; | 183 [description appendText:@"web view blocked resource with id "]; |
| 185 break; | 184 break; |
| 186 case IMAGE_STATE_LOADED: | 185 case IMAGE_STATE_LOADED: |
| 187 [description appendText:@"web view loaded resource with id "]; | 186 [description appendText:@"web view loaded resource with id "]; |
| 188 break; | 187 break; |
| 189 } | 188 } |
| 190 | 189 |
| 191 [description appendText:base::SysUTF8ToNSString(image_id)]; | 190 [description appendText:base::SysUTF8ToNSString(image_id)]; |
| 192 }; | 191 }; |
| 193 | 192 |
| 194 return grey_allOf(WebViewInWebState(web_state), | 193 return grey_allOf( |
| 195 [[[GREYElementMatcherBlock alloc] | 194 WebViewInWebState(web_state), |
| 196 initWithMatchesBlock:matches | 195 [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches |
| 197 descriptionBlock:describe] autorelease], | 196 descriptionBlock:describe], |
| 198 nil); | 197 nil); |
| 199 } | 198 } |
| 200 | 199 |
| 201 } // namespace | 200 } // namespace |
| 202 | 201 |
| 203 namespace web { | 202 namespace web { |
| 204 | 203 |
| 205 id<GREYMatcher> WebViewInWebState(WebState* web_state) { | 204 id<GREYMatcher> WebViewInWebState(WebState* web_state) { |
| 206 MatchesBlock matches = ^BOOL(UIView* view) { | 205 MatchesBlock matches = ^BOOL(UIView* view) { |
| 207 return [view isKindOfClass:[WKWebView class]] && | 206 return [view isKindOfClass:[WKWebView class]] && |
| 208 [view isDescendantOfView:web_state->GetView()]; | 207 [view isDescendantOfView:web_state->GetView()]; |
| 209 }; | 208 }; |
| 210 | 209 |
| 211 DescribeToBlock describe = ^(id<GREYDescription> description) { | 210 DescribeToBlock describe = ^(id<GREYDescription> description) { |
| 212 [description appendText:@"web view in web state"]; | 211 [description appendText:@"web view in web state"]; |
| 213 }; | 212 }; |
| 214 | 213 |
| 215 return [[[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches | 214 return [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches |
| 216 descriptionBlock:describe] | 215 descriptionBlock:describe]; |
| 217 autorelease]; | |
| 218 } | 216 } |
| 219 | 217 |
| 220 id<GREYMatcher> WebViewContainingText(std::string text, WebState* web_state) { | 218 id<GREYMatcher> WebViewContainingText(std::string text, WebState* web_state) { |
| 221 return WebViewWithText(text, web_state, true); | 219 return WebViewWithText(text, web_state, true); |
| 222 } | 220 } |
| 223 | 221 |
| 224 id<GREYMatcher> WebViewNotContainingText(std::string text, | 222 id<GREYMatcher> WebViewNotContainingText(std::string text, |
| 225 WebState* web_state) { | 223 WebState* web_state) { |
| 226 return WebViewWithText(text, web_state, false); | 224 return WebViewWithText(text, web_state, false); |
| 227 } | 225 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 249 } | 247 } |
| 250 return did_succeed; | 248 return did_succeed; |
| 251 }); | 249 }); |
| 252 }; | 250 }; |
| 253 | 251 |
| 254 DescribeToBlock describe = ^(id<GREYDescription> description) { | 252 DescribeToBlock describe = ^(id<GREYDescription> description) { |
| 255 [description appendText:@"web view selector "]; | 253 [description appendText:@"web view selector "]; |
| 256 [description appendText:base::SysUTF8ToNSString(selector)]; | 254 [description appendText:base::SysUTF8ToNSString(selector)]; |
| 257 }; | 255 }; |
| 258 | 256 |
| 259 return grey_allOf(WebViewInWebState(web_state), | 257 return grey_allOf( |
| 260 [[[GREYElementMatcherBlock alloc] | 258 WebViewInWebState(web_state), |
| 261 initWithMatchesBlock:matches | 259 [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches |
| 262 descriptionBlock:describe] autorelease], | 260 descriptionBlock:describe], |
| 263 nil); | 261 nil); |
| 264 } | 262 } |
| 265 | 263 |
| 266 id<GREYMatcher> WebViewScrollView(WebState* web_state) { | 264 id<GREYMatcher> WebViewScrollView(WebState* web_state) { |
| 267 MatchesBlock matches = ^BOOL(UIView* view) { | 265 MatchesBlock matches = ^BOOL(UIView* view) { |
| 268 return [view isKindOfClass:[UIScrollView class]] && | 266 return [view isKindOfClass:[UIScrollView class]] && |
| 269 [view.superview isKindOfClass:[WKWebView class]] && | 267 [view.superview isKindOfClass:[WKWebView class]] && |
| 270 [view isDescendantOfView:web_state->GetView()]; | 268 [view isDescendantOfView:web_state->GetView()]; |
| 271 }; | 269 }; |
| 272 | 270 |
| 273 DescribeToBlock describe = ^(id<GREYDescription> description) { | 271 DescribeToBlock describe = ^(id<GREYDescription> description) { |
| 274 [description appendText:@"web view scroll view"]; | 272 [description appendText:@"web view scroll view"]; |
| 275 }; | 273 }; |
| 276 | 274 |
| 277 return [[[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches | 275 return [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches |
| 278 descriptionBlock:describe] | 276 descriptionBlock:describe]; |
| 279 autorelease]; | |
| 280 } | 277 } |
| 281 | 278 |
| 282 id<GREYMatcher> Interstitial(WebState* web_state) { | 279 id<GREYMatcher> Interstitial(WebState* web_state) { |
| 283 MatchesBlock matches = ^BOOL(WKWebView* view) { | 280 MatchesBlock matches = ^BOOL(WKWebView* view) { |
| 284 web::WebInterstitialImpl* interstitial = | 281 web::WebInterstitialImpl* interstitial = |
| 285 static_cast<web::WebInterstitialImpl*>(web_state->GetWebInterstitial()); | 282 static_cast<web::WebInterstitialImpl*>(web_state->GetWebInterstitial()); |
| 286 return interstitial && | 283 return interstitial && |
| 287 [view isDescendantOfView:interstitial->GetContentView()]; | 284 [view isDescendantOfView:interstitial->GetContentView()]; |
| 288 }; | 285 }; |
| 289 | 286 |
| 290 DescribeToBlock describe = ^(id<GREYDescription> description) { | 287 DescribeToBlock describe = ^(id<GREYDescription> description) { |
| 291 [description appendText:@"interstitial displayed"]; | 288 [description appendText:@"interstitial displayed"]; |
| 292 }; | 289 }; |
| 293 | 290 |
| 294 return grey_allOf(WebViewInWebState(web_state), | 291 return grey_allOf( |
| 295 [[[GREYElementMatcherBlock alloc] | 292 WebViewInWebState(web_state), |
| 296 initWithMatchesBlock:matches | 293 [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches |
| 297 descriptionBlock:describe] autorelease], | 294 descriptionBlock:describe], |
| 298 nil); | 295 nil); |
| 299 } | 296 } |
| 300 | 297 |
| 301 id<GREYMatcher> InterstitialContainingText(NSString* text, | 298 id<GREYMatcher> InterstitialContainingText(NSString* text, |
| 302 WebState* web_state) { | 299 WebState* web_state) { |
| 303 MatchesBlock matches = ^BOOL(WKWebView* view) { | 300 MatchesBlock matches = ^BOOL(WKWebView* view) { |
| 304 return WaitUntilConditionOrTimeout(testing::kWaitForUIElementTimeout, ^{ | 301 return WaitUntilConditionOrTimeout(testing::kWaitForUIElementTimeout, ^{ |
| 305 NSString* script = base::SysUTF8ToNSString(kGetDocumentBodyJavaScript); | 302 NSString* script = base::SysUTF8ToNSString(kGetDocumentBodyJavaScript); |
| 306 id body = ExecuteScriptOnInterstitial(web_state, script); | 303 id body = ExecuteScriptOnInterstitial(web_state, script); |
| 307 return [body containsString:text] ? true : false; | 304 return [body containsString:text] ? true : false; |
| 308 }); | 305 }); |
| 309 }; | 306 }; |
| 310 | 307 |
| 311 DescribeToBlock describe = ^(id<GREYDescription> description) { | 308 DescribeToBlock describe = ^(id<GREYDescription> description) { |
| 312 [description appendText:@"interstitial containing "]; | 309 [description appendText:@"interstitial containing "]; |
| 313 [description appendText:text]; | 310 [description appendText:text]; |
| 314 }; | 311 }; |
| 315 | 312 |
| 316 return grey_allOf(Interstitial(web_state), | 313 return grey_allOf( |
| 317 [[[GREYElementMatcherBlock alloc] | 314 Interstitial(web_state), |
| 318 initWithMatchesBlock:matches | 315 [[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches |
| 319 descriptionBlock:describe] autorelease], | 316 descriptionBlock:describe], |
| 320 nil); | 317 nil); |
| 321 } | 318 } |
| 322 | 319 |
| 323 } // namespace web | 320 } // namespace web |
| OLD | NEW |