Index: ios/web/public/test/web_view_interaction_test_util.mm |
diff --git a/ios/web/public/test/web_view_interaction_test_util.mm b/ios/web/public/test/web_view_interaction_test_util.mm |
index 0892593c062af9f446a3938cc0ca0e822540e89e..d67bee907f3daa6feb582d71053f9bd8158c2431 100644 |
--- a/ios/web/public/test/web_view_interaction_test_util.mm |
+++ b/ios/web/public/test/web_view_interaction_test_util.mm |
@@ -4,9 +4,13 @@ |
#import "ios/web/public/test/web_view_interaction_test_util.h" |
-#import <Foundation/Foundation.h> |
- |
+#include "base/mac/bind_objc_block.h" |
+#include "base/strings/stringprintf.h" |
+#include "base/strings/utf_string_conversions.h" |
+#include "base/test/ios/wait_util.h" |
#include "ios/testing/earl_grey/wait_util.h" |
baxley
2016/08/31 05:27:02
Just an FYI. I am working on a CL to remove this d
marq (ping after 24h)
2016/08/31 13:07:58
Acknowledged.
|
+#import "ios/web/public/web_state/crw_web_view_scroll_view_proxy.h" |
+#import "ios/web/web_state/crw_web_view_proxy_impl.h" |
#import "ios/web/web_state/ui/crw_web_controller.h" |
#include "ios/web/web_state/web_state_impl.h" |
@@ -21,6 +25,98 @@ enum ElementAction { |
ELEMENT_ACTION_SUBMIT |
}; |
+std::unique_ptr<base::Value> ExecuteScript(web::WebState* web_state, |
+ const std::string& script) { |
+ __block std::unique_ptr<base::Value> result; |
+ __block bool did_finish = false; |
+ web_state->ExecuteJavaScript(base::UTF8ToUTF16(script), |
+ base::BindBlock(^(const base::Value* value) { |
+ if (value) |
+ result = value->CreateDeepCopy(); |
+ did_finish = true; |
+ })); |
+ |
+ testing::WaitUntilCondition(testing::kWaitForJSCompletionTimeout, ^{ |
+ return did_finish; |
+ }); |
+ |
+ // As result is marked __block, this return call does a copy and not a move |
+ // (marking the variable as __block mean it is allocated in the block object |
+ // and not the stack). Since the "return std::move()" pattern is discouraged |
+ // use a local variable. |
+ // |
+ // Fixes the following compilation failure: |
+ // ../web_view_matchers.mm:ll:cc: error: call to implicitly-deleted copy |
+ // constructor of 'std::unique_ptr<base::Value>' |
+ std::unique_ptr<base::Value> stack_result = std::move(result); |
+ return stack_result; |
+} |
+ |
+CGRect BoundingRectOfElementWithId(web::WebState* web_state, |
+ const std::string& element_id) { |
+ std::string kGetBoundsScript = |
+ "(function() {" |
+ " var element = document.getElementById('" + |
+ element_id + |
+ "');" |
+ " if (!element)" |
+ " return {'error': 'Element " + |
+ element_id + |
+ " not found'};" |
+ " var rect = element.getBoundingClientRect();" |
+ " var top = rect.top + document.body.scrollTop;" |
+ " var bottom = rect.bottom + document.body.scrollTop;" |
+ " var left = rect.left + document.body.scrollLeft;" |
+ " var right = rect.right + document.body.scrollLeft;" |
+ " return {" |
+ " 'left': left," |
+ " 'top': top," |
+ " 'width': right - left," |
+ " 'height': bottom - top," |
+ " 'document_width' : document.documentElement.scrollWidth," |
+ " 'document_height' : document.documentElement.scrollHeight," |
+ " };" |
+ "})();"; |
+ |
+ std::unique_ptr<base::Value> value; |
+ NSDate* deadline = |
+ [NSDate dateWithTimeIntervalSinceNow:testing::kWaitForUIElementTimeout]; |
+ while (([[NSDate date] compare:deadline] != NSOrderedDescending) && !value) { |
+ value = ExecuteScript(web_state, kGetBoundsScript); |
+ base::test::ios::SpinRunLoopWithMaxDelay( |
+ base::TimeDelta::FromSecondsD(testing::kSpinDelaySeconds)); |
+ } |
+ |
+ CGRect bounds = CGRectZero; |
Eugene But (OOO till 7-30)
2016/08/30 18:11:05
NIT: Do you need this variable? It's lifetime quit
marq (ping after 24h)
2016/08/31 13:07:58
Good catch, done.
|
+ base::DictionaryValue const* dictionary = nullptr; |
+ bool marshalling_ok = value->GetAsDictionary(&dictionary); |
+ std::string error; |
+ // If there is in error, then that's not OK, so the GetString return value |
+ // is negated here. |
+ marshalling_ok = marshalling_ok && !dictionary->GetString("error", &error); |
+ if (!marshalling_ok) |
+ return bounds; |
+ |
+ double left, top, width, height, document_width, document_height; |
+ marshalling_ok = marshalling_ok && dictionary->GetDouble("left", &left) && |
+ dictionary->GetDouble("top", &top) && |
+ dictionary->GetDouble("width", &width) && |
+ dictionary->GetDouble("height", &height) && |
+ dictionary->GetDouble("document_width", &document_width) && |
+ dictionary->GetDouble("document_height", &document_height); |
+ |
+ if (!marshalling_ok) |
+ return bounds; |
+ |
+ CRWWebController* web_controller = |
+ static_cast<WebStateImpl*>(web_state)->GetWebController(); |
+ |
+ CGFloat scale = [[web_controller.webViewProxy scrollViewProxy] zoomScale]; |
Eugene But (OOO till 7-30)
2016/08/30 18:11:05
No need to use web controller here:
web_state->Ge
marq (ping after 24h)
2016/08/31 13:07:58
Done.
|
+ |
+ bounds = CGRectMake(left * scale, top * scale, width * scale, height * scale); |
+ return bounds; |
+} |
+ |
// Returns whether the Javascript action specified by |action| ran on |
// |element_id| in the passed |web_state|. |
bool RunActionOnWebViewElementWithId(web::WebState* web_state, |