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/web_view_interaction_test_util.h" | 5 #import "ios/web/public/test/web_view_interaction_test_util.h" |
6 | 6 |
7 #import <Foundation/Foundation.h> | 7 #include "base/mac/bind_objc_block.h" |
8 | 8 #include "base/strings/stringprintf.h" |
| 9 #include "base/strings/utf_string_conversions.h" |
| 10 #include "base/test/ios/wait_util.h" |
9 #include "ios/testing/earl_grey/wait_util.h" | 11 #include "ios/testing/earl_grey/wait_util.h" |
| 12 #import "ios/web/public/web_state/crw_web_view_scroll_view_proxy.h" |
| 13 #import "ios/web/web_state/crw_web_view_proxy_impl.h" |
10 #import "ios/web/web_state/ui/crw_web_controller.h" | 14 #import "ios/web/web_state/ui/crw_web_controller.h" |
11 #include "ios/web/web_state/web_state_impl.h" | 15 #include "ios/web/web_state/web_state_impl.h" |
12 | 16 |
13 using web::NavigationManager; | 17 using web::NavigationManager; |
14 | 18 |
15 namespace web { | 19 namespace web { |
16 namespace test { | 20 namespace test { |
17 | 21 |
18 enum ElementAction { | 22 enum ElementAction { |
19 ELEMENT_ACTION_CLICK, | 23 ELEMENT_ACTION_CLICK, |
20 ELEMENT_ACTION_FOCUS, | 24 ELEMENT_ACTION_FOCUS, |
21 ELEMENT_ACTION_SUBMIT | 25 ELEMENT_ACTION_SUBMIT |
22 }; | 26 }; |
23 | 27 |
| 28 std::unique_ptr<base::Value> ExecuteJavaScript(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 CGRect GetBoundingRectOfElementWithId(web::WebState* web_state, |
| 56 const std::string& element_id) { |
| 57 std::string kGetBoundsScript = |
| 58 "(function() {" |
| 59 " var element = document.getElementById('" + |
| 60 element_id + |
| 61 "');" |
| 62 " if (!element)" |
| 63 " return {'error': 'Element " + |
| 64 element_id + |
| 65 " not found'};" |
| 66 " var rect = element.getBoundingClientRect();" |
| 67 " var top = rect.top + document.body.scrollTop;" |
| 68 " var bottom = rect.bottom + document.body.scrollTop;" |
| 69 " var left = rect.left + document.body.scrollLeft;" |
| 70 " var right = rect.right + document.body.scrollLeft;" |
| 71 " return {" |
| 72 " 'left': left," |
| 73 " 'top': top," |
| 74 " 'width': right - left," |
| 75 " 'height': bottom - top," |
| 76 " 'document_width' : document.documentElement.scrollWidth," |
| 77 " 'document_height' : document.documentElement.scrollHeight," |
| 78 " };" |
| 79 "})();"; |
| 80 |
| 81 base::DictionaryValue const* rect = nullptr; |
| 82 bool found = false; |
| 83 NSDate* deadline = |
| 84 [NSDate dateWithTimeIntervalSinceNow:testing::kWaitForUIElementTimeout]; |
| 85 while (([[NSDate date] compare:deadline] != NSOrderedDescending) && !found) { |
| 86 std::unique_ptr<base::Value> value = |
| 87 ExecuteJavaScript(web_state, kGetBoundsScript); |
| 88 base::DictionaryValue* dictionary = nullptr; |
| 89 if (value && value->GetAsDictionary(&dictionary)) { |
| 90 std::string error; |
| 91 if (dictionary->GetString("error", &error)) { |
| 92 DLOG(ERROR) << "Error getting rect: " << error << ", retrying.."; |
| 93 } else { |
| 94 rect = dictionary->DeepCopy(); |
| 95 found = true; |
| 96 } |
| 97 } |
| 98 base::test::ios::SpinRunLoopWithMaxDelay( |
| 99 base::TimeDelta::FromSecondsD(testing::kSpinDelaySeconds)); |
| 100 } |
| 101 |
| 102 if (!found) |
| 103 return CGRectNull; |
| 104 |
| 105 double left, top, width, height, document_width, document_height; |
| 106 if (!(rect->GetDouble("left", &left) && rect->GetDouble("top", &top) && |
| 107 rect->GetDouble("width", &width) && |
| 108 rect->GetDouble("height", &height) && |
| 109 rect->GetDouble("document_width", &document_width) && |
| 110 rect->GetDouble("document_height", &document_height))) { |
| 111 return CGRectNull; |
| 112 } |
| 113 |
| 114 CGFloat scale = [[web_state->GetWebViewProxy() scrollViewProxy] zoomScale]; |
| 115 |
| 116 return CGRectMake(left * scale, top * scale, width * scale, height * scale); |
| 117 } |
| 118 |
24 // Returns whether the Javascript action specified by |action| ran on | 119 // Returns whether the Javascript action specified by |action| ran on |
25 // |element_id| in the passed |web_state|. | 120 // |element_id| in the passed |web_state|. |
26 bool RunActionOnWebViewElementWithId(web::WebState* web_state, | 121 bool RunActionOnWebViewElementWithId(web::WebState* web_state, |
27 const std::string& element_id, | 122 const std::string& element_id, |
28 ElementAction action) { | 123 ElementAction action) { |
29 CRWWebController* web_controller = | 124 CRWWebController* web_controller = |
30 static_cast<WebStateImpl*>(web_state)->GetWebController(); | 125 static_cast<WebStateImpl*>(web_state)->GetWebController(); |
31 const char* js_action = nullptr; | 126 const char* js_action = nullptr; |
32 switch (action) { | 127 switch (action) { |
33 case ELEMENT_ACTION_CLICK: | 128 case ELEMENT_ACTION_CLICK: |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 } | 173 } |
79 | 174 |
80 bool SubmitWebViewFormWithId(web::WebState* web_state, | 175 bool SubmitWebViewFormWithId(web::WebState* web_state, |
81 const std::string& form_id) { | 176 const std::string& form_id) { |
82 return RunActionOnWebViewElementWithId(web_state, form_id, | 177 return RunActionOnWebViewElementWithId(web_state, form_id, |
83 ELEMENT_ACTION_SUBMIT); | 178 ELEMENT_ACTION_SUBMIT); |
84 } | 179 } |
85 | 180 |
86 } // namespace test | 181 } // namespace test |
87 } // namespace web | 182 } // namespace web |
OLD | NEW |