Skip to content

Commit b9b2f22

Browse files
committed
Fixing getElementProperty to return proper data type.
Previously, the getElementProperty command would coerce the property value to a string. This is not correct behavior as specified in the W3C spec.
1 parent 6d505cc commit b9b2f22

9 files changed

+49
-112
lines changed

cpp/iedriver/CommandHandlers/GetElementAttributeCommandHandler.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "../Browser.h"
2020
#include "../Element.h"
2121
#include "../IECommandExecutor.h"
22+
#include "../VariantUtilities.h"
2223

2324
namespace webdriver {
2425

@@ -54,22 +55,20 @@ void GetElementAttributeCommandHandler::ExecuteInternal(
5455
ElementHandle element_wrapper;
5556
status_code = this->GetElement(executor, element_id, &element_wrapper);
5657
if (status_code == WD_SUCCESS) {
57-
std::string value = "";
58-
bool is_null;
58+
CComVariant attribute_value;
59+
IECommandExecutor& mutable_executor = const_cast<IECommandExecutor&>(executor);
60+
Json::Value value;
5961
status_code = element_wrapper->GetAttributeValue(name,
60-
&value,
61-
&is_null);
62+
&attribute_value);
63+
VariantUtilities::VariantAsJsonValue(mutable_executor.element_manager(),
64+
attribute_value,
65+
&value);
6266
if (status_code != WD_SUCCESS) {
6367
response->SetErrorResponse(status_code, "Unable to get attribute");
6468
return;
6569
} else {
66-
if (is_null) {
67-
response->SetSuccessResponse(Json::Value::null);
68-
return;
69-
} else {
70-
response->SetSuccessResponse(value);
71-
return;
72-
}
70+
response->SetSuccessResponse(value);
71+
return;
7372
}
7473
} else if (status_code == ENOSUCHELEMENT) {
7574
response->SetErrorResponse(ERROR_NO_SUCH_ELEMENT, "Invalid internal element ID requested: " + element_id);

cpp/iedriver/CommandHandlers/GetElementPropertyCommandHandler.cpp

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "../Browser.h"
2020
#include "../Element.h"
2121
#include "../IECommandExecutor.h"
22+
#include "../VariantUtilities.h"
2223

2324
namespace webdriver {
2425

@@ -54,22 +55,18 @@ void GetElementPropertyCommandHandler::ExecuteInternal(
5455
ElementHandle element_wrapper;
5556
status_code = this->GetElement(executor, element_id, &element_wrapper);
5657
if (status_code == WD_SUCCESS) {
57-
std::string value = "";
58-
bool is_null;
58+
CComVariant value;
5959
status_code = element_wrapper->GetPropertyValue(name,
60-
&value,
61-
&is_null);
60+
&value);
6261
if (status_code != WD_SUCCESS) {
6362
response->SetErrorResponse(status_code, "Unable to get property");
6463
return;
6564
} else {
66-
if (is_null) {
67-
response->SetSuccessResponse(Json::Value::null);
68-
return;
69-
} else {
70-
response->SetSuccessResponse(value);
71-
return;
72-
}
65+
Json::Value json_value;
66+
IECommandExecutor& mutable_executor = const_cast<IECommandExecutor&>(executor);
67+
VariantUtilities::VariantAsJsonValue(mutable_executor.element_manager(), value, &json_value);
68+
response->SetSuccessResponse(json_value);
69+
return;
7370
}
7471
} else if (status_code == ENOSUCHELEMENT) {
7572
response->SetErrorResponse(ERROR_NO_SUCH_ELEMENT, "Invalid internal element ID requested: " + element_id);

cpp/iedriver/CommandHandlers/GetElementTextCommandHandler.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,22 @@ void GetElementTextCommandHandler::ExecuteInternal(
6666
status_code = script_wrapper.Execute();
6767

6868
if (status_code == WD_SUCCESS) {
69-
std::string text = "";
70-
bool is_null = script_wrapper.ConvertResultToString(&text);
71-
response->SetSuccessResponse(text);
69+
Json::Value text_value;
70+
IECommandExecutor& mutable_executor = const_cast<IECommandExecutor&>(executor);
71+
int is_null = script_wrapper.ConvertResultToJsonValue(mutable_executor.element_manager(), &text_value);
72+
if (!text_value.isString()) {
73+
// This really should never happen, since we're executing an atom
74+
// over which we have complete control. Nevertheless, check for
75+
// the error here, just in case.
76+
response->SetErrorResponse(ERROR_JAVASCRIPT_ERROR,
77+
"Atom retrieving text was executed, but did not return a string");
78+
return;
79+
}
80+
response->SetSuccessResponse(text_value.asString());
7281
return;
7382
} else {
7483
response->SetErrorResponse(status_code,
75-
"Unable to get element text");
84+
"Unable to get element text");
7685
return;
7786
}
7887
} else if (status_code == ENOSUCHELEMENT) {

cpp/iedriver/Element.cpp

Lines changed: 16 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,7 @@ int Element::GetClickLocation(const ElementScrollBehavior scroll_behavior,
246246
}
247247

248248
int Element::GetAttributeValue(const std::string& attribute_name,
249-
std::string* attribute_value,
250-
bool* value_is_null) {
249+
VARIANT* attribute_value) {
251250
LOG(TRACE) << "Entering Element::GetAttributeValue";
252251

253252
std::wstring wide_attribute_name = StringUtilities::ToWString(attribute_name);
@@ -268,7 +267,7 @@ int Element::GetAttributeValue(const std::string& attribute_name,
268267
status_code = script_wrapper.Execute();
269268

270269
if (status_code == WD_SUCCESS) {
271-
*value_is_null = !script_wrapper.ConvertResultToString(attribute_value);
270+
*attribute_value = script_wrapper.result();
272271
} else {
273272
LOG(WARN) << "Failed to determine element attribute";
274273
}
@@ -277,8 +276,7 @@ int Element::GetAttributeValue(const std::string& attribute_name,
277276
}
278277

279278
int Element::GetPropertyValue(const std::string& property_name,
280-
std::string* property_value,
281-
bool* value_is_null) {
279+
VARIANT* property_value) {
282280
LOG(TRACE) << "Entering Element::GetPropertyValue";
283281

284282
std::wstring wide_property_name = StringUtilities::ToWString(property_name);
@@ -294,36 +292,27 @@ int Element::GetPropertyValue(const std::string& property_name,
294292
if (FAILED(hr)) {
295293
LOGHR(WARN, hr) << "Unable to get dispatch ID (dispid) for property "
296294
<< property_name;
297-
*property_value = "";
298-
*value_is_null = true;
295+
property_value->vt = VT_EMPTY;
299296
return WD_SUCCESS;
300297
}
301298

302299
// get the value of eval result
303-
CComVariant property_value_variant;
304300
DISPPARAMS no_args_dispatch_parameters = { 0 };
305301
hr = this->element_->Invoke(dispid_property,
306302
IID_NULL,
307303
LOCALE_USER_DEFAULT,
308304
DISPATCH_PROPERTYGET,
309305
&no_args_dispatch_parameters,
310-
&property_value_variant,
306+
property_value,
311307
NULL,
312308
NULL);
313309
if (FAILED(hr)) {
314310
LOGHR(WARN, hr) << "Unable to get result for property "
315311
<< property_name;
316-
*property_value = "";
317-
*value_is_null = true;
312+
property_value->vt = VT_EMPTY;
318313
return WD_SUCCESS;
319314
}
320315

321-
if (status_code == WD_SUCCESS) {
322-
*value_is_null = !VariantUtilities::VariantAsString(property_value_variant, property_value);
323-
} else {
324-
LOG(WARN) << "Failed to determine element attribute";
325-
}
326-
327316
return WD_SUCCESS;
328317
}
329318

@@ -347,13 +336,13 @@ int Element::GetCssPropertyValue(const std::string& property_name,
347336
status_code = script_wrapper.Execute();
348337

349338
if (status_code == WD_SUCCESS) {
350-
std::string raw_value = "";
351-
script_wrapper.ConvertResultToString(&raw_value);
339+
std::wstring raw_value(script_wrapper.result().bstrVal);
340+
std::string value = StringUtilities::ToString(raw_value);
352341
std::transform(raw_value.begin(),
353-
raw_value.end(),
354-
raw_value.begin(),
355-
tolower);
356-
*property_value = raw_value;
342+
raw_value.end(),
343+
raw_value.begin(),
344+
tolower);
345+
*property_value = value;
357346
} else {
358347
LOG(WARN) << "Failed to get value of CSS property";
359348
}
@@ -444,8 +433,8 @@ bool Element::IsHiddenByOverflow() {
444433
script_wrapper.AddArgument(this->element_);
445434
int status_code = script_wrapper.Execute();
446435
if (status_code == WD_SUCCESS) {
447-
std::string overflow_state = "";
448-
script_wrapper.ConvertResultToString(&overflow_state);
436+
std::wstring raw_overflow_state(script_wrapper.result().bstrVal);
437+
std::string overflow_state = StringUtilities::ToString(raw_overflow_state);
449438
isOverflow = (overflow_state == "scroll");
450439
} else {
451440
LOG(WARN) << "Unable to determine is element hidden by overflow";
@@ -454,7 +443,8 @@ bool Element::IsHiddenByOverflow() {
454443
return isOverflow;
455444
}
456445

457-
bool Element::IsLocationVisibleInFrames(const LocationInfo location, const std::vector<LocationInfo> frame_locations) {
446+
bool Element::IsLocationVisibleInFrames(const LocationInfo location,
447+
const std::vector<LocationInfo> frame_locations) {
458448
std::vector<LocationInfo>::const_iterator iterator = frame_locations.begin();
459449
for (; iterator != frame_locations.end(); ++iterator) {
460450
if (location.x < iterator->x ||

cpp/iedriver/Element.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,9 @@ class Element {
5252
LocationInfo* element_location,
5353
LocationInfo* click_location);
5454
int GetAttributeValue(const std::string& attribute_name,
55-
std::string* attribute_value,
56-
bool* value_is_null);
55+
VARIANT* attribute_value);
5756
int GetPropertyValue(const std::string& property_name,
58-
std::string* property_value,
59-
bool* value_is_null);
57+
VARIANT* property_value);
6058
int GetCssPropertyValue(const std::string& property_name,
6159
std::string* property_value);
6260

cpp/iedriver/Script.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -555,11 +555,6 @@ int Script::ConvertResultToJsonValue(IElementManager* element_manager,
555555
value);
556556
}
557557

558-
bool Script::ConvertResultToString(std::string* value) {
559-
LOG(TRACE) << "Entering Script::ConvertResultToString";
560-
return VariantUtilities::VariantAsString(this->result_, value);
561-
}
562-
563558
bool Script::CreateAnonymousFunction(VARIANT* result) {
564559
LOG(TRACE) << "Entering Script::CreateAnonymousFunction";
565560

cpp/iedriver/Script.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ class Script {
101101
Json::Value* value);
102102
int ConvertResultToJsonValue(IElementManager* element_manager,
103103
Json::Value* value);
104-
bool ConvertResultToString(std::string* value);
105104

106105
std::wstring polling_source_code(void) const { return this->polling_source_code_; }
107106
void set_polling_source_code(const std::wstring& value) { this->polling_source_code_ = value; }

cpp/iedriver/VariantUtilities.cpp

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -122,54 +122,6 @@ bool VariantUtilities::VariantIsObject(VARIANT value) {
122122
return false;
123123
}
124124

125-
bool VariantUtilities::VariantAsString(VARIANT variant_value,
126-
std::string* value) {
127-
VARTYPE type = variant_value.vt;
128-
switch (type) {
129-
130-
case VT_BOOL:
131-
LOG(DEBUG) << "Result type is boolean";
132-
*value = variant_value.boolVal == VARIANT_TRUE ? "true" : "false";
133-
return true;
134-
135-
case VT_BSTR:
136-
LOG(DEBUG) << "Result type is string";
137-
if (!variant_value.bstrVal) {
138-
*value = "";
139-
} else {
140-
std::wstring str_value = variant_value.bstrVal;
141-
*value = StringUtilities::ToString(str_value);
142-
}
143-
return true;
144-
145-
case VT_I4:
146-
LOG(DEBUG) << "Result type is int";
147-
*value = std::to_string(static_cast<long long>(variant_value.lVal));
148-
return true;
149-
150-
case VT_R4:
151-
LOG(DEBUG) << "Result type is real";
152-
*value = std::to_string(variant_value.dblVal);
153-
return true;
154-
155-
case VT_EMPTY:
156-
case VT_NULL:
157-
LOG(DEBUG) << "Result type is empty";
158-
*value = "";
159-
return false;
160-
161-
// This is lame
162-
case VT_DISPATCH:
163-
LOG(DEBUG) << "Result type is dispatch";
164-
*value = "";
165-
return true;
166-
167-
default:
168-
LOG(DEBUG) << "Result type is unknown: " << type;
169-
}
170-
return false;
171-
}
172-
173125
int VariantUtilities::VariantAsJsonValue(IElementManager* element_manager,
174126
VARIANT variant_value,
175127
Json::Value* value) {

cpp/iedriver/VariantUtilities.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ class VariantUtilities {
5151
static int VariantAsJsonValue(IElementManager* element_manager,
5252
VARIANT variant_value,
5353
Json::Value* value);
54-
static bool VariantAsString(VARIANT variant_value,
55-
std::string* value);
5654
static bool GetVariantObjectPropertyValue(IDispatch* variant_object,
5755
std::wstring property_name,
5856
VARIANT* property_value);

0 commit comments

Comments
 (0)