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 |