Chromium Code Reviews| 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 #include <memory> | |
| 8 | |
| 9 #import <WebKit/WebKit.h> | 7 #import <WebKit/WebKit.h> |
| 10 | 8 |
| 11 #include "base/mac/bind_objc_block.h" | 9 #include "base/mac/bind_objc_block.h" |
| 12 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
| 13 #include "base/strings/sys_string_conversions.h" | 11 #include "base/strings/sys_string_conversions.h" |
| 14 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
| 15 #include "base/test/ios/wait_util.h" | 13 #include "base/test/ios/wait_util.h" |
| 16 #include "base/values.h" | 14 #include "base/values.h" |
| 17 #include "ios/testing/earl_grey/wait_util.h" | 15 #include "ios/testing/earl_grey/wait_util.h" |
| 16 #import "ios/web/public/test/web_view_interaction_test_util.h" | |
| 17 | |
| 18 using web::test::ExecuteJavaScript; | |
| 18 | 19 |
| 19 namespace { | 20 namespace { |
| 20 | 21 |
| 21 // Script that returns document.body as a string. | 22 // Script that returns document.body as a string. |
| 22 char kGetDocumentBodyJavaScript[] = | 23 char kGetDocumentBodyJavaScript[] = |
| 23 "document.body ? document.body.textContent : null"; | 24 "document.body ? document.body.textContent : null"; |
| 24 // Script that tests presence of css selector. | 25 // Script that tests presence of css selector. |
| 25 char kTestCssSelectorJavaScriptTemplate[] = "!!document.querySelector(\"%s\");"; | 26 char kTestCssSelectorJavaScriptTemplate[] = "!!document.querySelector(\"%s\");"; |
| 26 | 27 |
| 27 // Synchronously returns the result of executed JavaScript. | |
| 28 std::unique_ptr<base::Value> ExecuteScript(web::WebState* web_state, | |
| 29 const std::string& script) { | |
| 30 __block std::unique_ptr<base::Value> result; | |
| 31 __block bool did_finish = false; | |
| 32 web_state->ExecuteJavaScript(base::UTF8ToUTF16(script), | |
| 33 base::BindBlock(^(const base::Value* value) { | |
| 34 if (value) | |
| 35 result = value->CreateDeepCopy(); | |
| 36 did_finish = true; | |
| 37 })); | |
| 38 | |
| 39 testing::WaitUntilCondition(testing::kWaitForJSCompletionTimeout, ^{ | |
| 40 return did_finish; | |
| 41 }); | |
| 42 | |
| 43 // As result is marked __block, this return call does a copy and not a move | |
| 44 // (marking the variable as __block mean it is allocated in the block object | |
| 45 // and not the stack). Since the "return std::move()" pattern is discouraged | |
| 46 // use a local variable. | |
| 47 // | |
| 48 // Fixes the following compilation failure: | |
| 49 // ../web_view_matchers.mm:ll:cc: error: call to implicitly-deleted copy | |
| 50 // constructor of 'std::unique_ptr<base::Value>' | |
| 51 std::unique_ptr<base::Value> stack_result = std::move(result); | |
| 52 return stack_result; | |
| 53 } | |
| 54 | |
| 55 } // namespace | 28 } // namespace |
| 56 | 29 |
| 57 namespace web { | 30 namespace web { |
| 58 | 31 |
| 59 id<GREYMatcher> webViewInWebState(WebState* web_state) { | 32 id<GREYMatcher> webViewInWebState(WebState* web_state) { |
| 60 MatchesBlock matches = ^BOOL(UIView* view) { | 33 MatchesBlock matches = ^BOOL(UIView* view) { |
| 61 return [view isKindOfClass:[WKWebView class]] && | 34 return [view isKindOfClass:[WKWebView class]] && |
| 62 [view isDescendantOfView:web_state->GetView()]; | 35 [view isDescendantOfView:web_state->GetView()]; |
| 63 }; | 36 }; |
| 64 | 37 |
| 65 DescribeToBlock describe = ^(id<GREYDescription> description) { | 38 DescribeToBlock describe = ^(id<GREYDescription> description) { |
| 66 [description appendText:@"web view in web state"]; | 39 [description appendText:@"web view in web state"]; |
| 67 }; | 40 }; |
| 68 | 41 |
| 69 return [[[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches | 42 return [[[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches |
| 70 descriptionBlock:describe] | 43 descriptionBlock:describe] |
| 71 autorelease]; | 44 autorelease]; |
| 72 } | 45 } |
| 73 | 46 |
| 74 id<GREYMatcher> webViewContainingText(std::string text, WebState* web_state) { | 47 id<GREYMatcher> webViewContainingText(const std::string& text, |
|
Eugene But (OOO till 7-30)
2016/08/31 15:27:59
This should be string by value or local variable (
| |
| 48 WebState* web_state) { | |
| 75 MatchesBlock matches = ^BOOL(WKWebView*) { | 49 MatchesBlock matches = ^BOOL(WKWebView*) { |
| 76 __block BOOL did_succeed = NO; | 50 __block BOOL did_succeed = NO; |
| 77 NSDate* deadline = | 51 NSDate* deadline = |
| 78 [NSDate dateWithTimeIntervalSinceNow:testing::kWaitForUIElementTimeout]; | 52 [NSDate dateWithTimeIntervalSinceNow:testing::kWaitForUIElementTimeout]; |
| 79 while (([[NSDate date] compare:deadline] != NSOrderedDescending) && | 53 while (([[NSDate date] compare:deadline] != NSOrderedDescending) && |
| 80 !did_succeed) { | 54 !did_succeed) { |
| 81 std::unique_ptr<base::Value> value = | 55 std::unique_ptr<base::Value> value = |
| 82 ExecuteScript(web_state, kGetDocumentBodyJavaScript); | 56 ExecuteJavaScript(web_state, kGetDocumentBodyJavaScript); |
| 83 std::string body; | 57 std::string body; |
| 84 if (value && value->GetAsString(&body)) { | 58 if (value && value->GetAsString(&body)) { |
| 85 did_succeed = body.find(text) != std::string::npos; | 59 did_succeed = body.find(text) != std::string::npos; |
| 86 } | 60 } |
| 87 base::test::ios::SpinRunLoopWithMaxDelay( | 61 base::test::ios::SpinRunLoopWithMaxDelay( |
| 88 base::TimeDelta::FromSecondsD(testing::kSpinDelaySeconds)); | 62 base::TimeDelta::FromSecondsD(testing::kSpinDelaySeconds)); |
| 89 } | 63 } |
| 90 return did_succeed; | 64 return did_succeed; |
| 91 }; | 65 }; |
| 92 | 66 |
| 93 DescribeToBlock describe = ^(id<GREYDescription> description) { | 67 DescribeToBlock describe = ^(id<GREYDescription> description) { |
| 94 [description appendText:@"web view containing "]; | 68 [description appendText:@"web view containing "]; |
| 95 [description appendText:base::SysUTF8ToNSString(text)]; | 69 [description appendText:base::SysUTF8ToNSString(text)]; |
| 96 }; | 70 }; |
| 97 | 71 |
| 98 return grey_allOf(webViewInWebState(web_state), | 72 return grey_allOf(webViewInWebState(web_state), |
| 99 [[[GREYElementMatcherBlock alloc] | 73 [[[GREYElementMatcherBlock alloc] |
| 100 initWithMatchesBlock:matches | 74 initWithMatchesBlock:matches |
| 101 descriptionBlock:describe] autorelease], | 75 descriptionBlock:describe] autorelease], |
| 102 nil); | 76 nil); |
| 103 } | 77 } |
| 104 | 78 |
| 105 id<GREYMatcher> webViewContainingBlockedImage(std::string image_id, | 79 id<GREYMatcher> webViewContainingBlockedImage(const std::string& image_id, |
|
Eugene But (OOO till 7-30)
2016/08/31 15:27:59
ditto
| |
| 106 CGSize expected_size, | 80 CGSize expected_size, |
| 107 WebState* web_state) { | 81 WebState* web_state) { |
| 108 MatchesBlock matches = ^BOOL(WKWebView*) { | 82 MatchesBlock matches = ^BOOL(WKWebView*) { |
| 109 __block BOOL did_succeed = NO; | 83 __block BOOL did_succeed = NO; |
| 110 NSDate* deadline = | 84 NSDate* deadline = |
| 111 [NSDate dateWithTimeIntervalSinceNow:testing::kWaitForUIElementTimeout]; | 85 [NSDate dateWithTimeIntervalSinceNow:testing::kWaitForUIElementTimeout]; |
| 112 while (([[NSDate date] compare:deadline] != NSOrderedDescending) && | 86 while (([[NSDate date] compare:deadline] != NSOrderedDescending) && |
| 113 !did_succeed) { | 87 !did_succeed) { |
| 114 NSString* const kGetElementAttributesScript = [NSString | 88 NSString* const kGetElementAttributesScript = [NSString |
| 115 stringWithFormat:@"var image = document.getElementById('%@');" | 89 stringWithFormat:@"var image = document.getElementById('%@');" |
| 116 @"var imageHeight = image.height;" | 90 @"var imageHeight = image.height;" |
| 117 @"var imageWidth = image.width;" | 91 @"var imageWidth = image.width;" |
| 118 @"JSON.stringify({" | 92 @"JSON.stringify({" |
| 119 @" height:imageHeight," | 93 @" height:imageHeight," |
| 120 @" width:imageWidth" | 94 @" width:imageWidth" |
| 121 @"});", | 95 @"});", |
| 122 base::SysUTF8ToNSString(image_id)]; | 96 base::SysUTF8ToNSString(image_id)]; |
| 123 std::unique_ptr<base::Value> value = ExecuteScript( | 97 std::unique_ptr<base::Value> value = ExecuteJavaScript( |
| 124 web_state, base::SysNSStringToUTF8(kGetElementAttributesScript)); | 98 web_state, base::SysNSStringToUTF8(kGetElementAttributesScript)); |
| 125 std::string result; | 99 std::string result; |
| 126 if (value && value->GetAsString(&result)) { | 100 if (value && value->GetAsString(&result)) { |
| 127 NSString* evaluation_result = base::SysUTF8ToNSString(result); | 101 NSString* evaluation_result = base::SysUTF8ToNSString(result); |
| 128 NSData* image_attributes_as_data = | 102 NSData* image_attributes_as_data = |
| 129 [evaluation_result dataUsingEncoding:NSUTF8StringEncoding]; | 103 [evaluation_result dataUsingEncoding:NSUTF8StringEncoding]; |
| 130 NSDictionary* image_attributes = | 104 NSDictionary* image_attributes = |
| 131 [NSJSONSerialization JSONObjectWithData:image_attributes_as_data | 105 [NSJSONSerialization JSONObjectWithData:image_attributes_as_data |
| 132 options:0 | 106 options:0 |
| 133 error:nil]; | 107 error:nil]; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 147 [description appendText:base::SysUTF8ToNSString(image_id)]; | 121 [description appendText:base::SysUTF8ToNSString(image_id)]; |
| 148 }; | 122 }; |
| 149 | 123 |
| 150 return grey_allOf(webViewInWebState(web_state), | 124 return grey_allOf(webViewInWebState(web_state), |
| 151 [[[GREYElementMatcherBlock alloc] | 125 [[[GREYElementMatcherBlock alloc] |
| 152 initWithMatchesBlock:matches | 126 initWithMatchesBlock:matches |
| 153 descriptionBlock:describe] autorelease], | 127 descriptionBlock:describe] autorelease], |
| 154 nil); | 128 nil); |
| 155 } | 129 } |
| 156 | 130 |
| 157 id<GREYMatcher> webViewCssSelector(std::string selector, WebState* web_state) { | 131 id<GREYMatcher> webViewCssSelector(const std::string& selector, |
|
Eugene But (OOO till 7-30)
2016/08/31 15:27:59
ditto
| |
| 132 WebState* web_state) { | |
| 158 MatchesBlock matches = ^BOOL(WKWebView*) { | 133 MatchesBlock matches = ^BOOL(WKWebView*) { |
| 159 std::string script = base::StringPrintf(kTestCssSelectorJavaScriptTemplate, | 134 std::string script = base::StringPrintf(kTestCssSelectorJavaScriptTemplate, |
| 160 selector.c_str()); | 135 selector.c_str()); |
| 161 __block bool did_succeed = false; | 136 __block bool did_succeed = false; |
| 162 NSDate* deadline = | 137 NSDate* deadline = |
| 163 [NSDate dateWithTimeIntervalSinceNow:testing::kWaitForUIElementTimeout]; | 138 [NSDate dateWithTimeIntervalSinceNow:testing::kWaitForUIElementTimeout]; |
| 164 while (([[NSDate date] compare:deadline] != NSOrderedDescending) && | 139 while (([[NSDate date] compare:deadline] != NSOrderedDescending) && |
| 165 !did_succeed) { | 140 !did_succeed) { |
| 166 std::unique_ptr<base::Value> value = ExecuteScript(web_state, script); | 141 std::unique_ptr<base::Value> value = ExecuteJavaScript(web_state, script); |
| 167 if (value) | 142 if (value) |
| 168 value->GetAsBoolean(&did_succeed); | 143 value->GetAsBoolean(&did_succeed); |
| 169 base::test::ios::SpinRunLoopWithMaxDelay( | 144 base::test::ios::SpinRunLoopWithMaxDelay( |
| 170 base::TimeDelta::FromSecondsD(testing::kSpinDelaySeconds)); | 145 base::TimeDelta::FromSecondsD(testing::kSpinDelaySeconds)); |
| 171 } | 146 } |
| 172 return did_succeed; | 147 return did_succeed; |
| 173 }; | 148 }; |
| 174 | 149 |
| 175 DescribeToBlock describe = ^(id<GREYDescription> description) { | 150 DescribeToBlock describe = ^(id<GREYDescription> description) { |
| 176 [description appendText:@"web view selector "]; | 151 [description appendText:@"web view selector "]; |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 194 DescribeToBlock describe = ^(id<GREYDescription> description) { | 169 DescribeToBlock describe = ^(id<GREYDescription> description) { |
| 195 [description appendText:@"web view scroll view"]; | 170 [description appendText:@"web view scroll view"]; |
| 196 }; | 171 }; |
| 197 | 172 |
| 198 return [[[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches | 173 return [[[GREYElementMatcherBlock alloc] initWithMatchesBlock:matches |
| 199 descriptionBlock:describe] | 174 descriptionBlock:describe] |
| 200 autorelease]; | 175 autorelease]; |
| 201 } | 176 } |
| 202 | 177 |
| 203 } // namespace web | 178 } // namespace web |
| OLD | NEW |