예제 #1
0
int Element::GetAttributeValue(const std::string& attribute_name,
                               std::string* attribute_value,
                               bool* value_is_null) {
  LOG(TRACE) << "Entering Element::GetAttributeValue";

  std::wstring wide_attribute_name = StringUtilities::ToWString(attribute_name);
  int status_code = WD_SUCCESS;

  // The atom is just the definition of an anonymous
  // function: "function() {...}"; Wrap it in another function so we can
  // invoke it with our arguments without polluting the current namespace.
  std::wstring script_source(L"(function() { return (");
  script_source += atoms::asString(atoms::GET_ATTRIBUTE);
  script_source += L")})();";

  CComPtr<IHTMLDocument2> doc;
  this->GetContainingDocument(false, &doc);
  Script script_wrapper(doc, script_source, 2);
  script_wrapper.AddArgument(this->element_);
  script_wrapper.AddArgument(wide_attribute_name);
  status_code = script_wrapper.Execute();
  
  if (status_code == WD_SUCCESS) {
    *value_is_null = !script_wrapper.ConvertResultToString(attribute_value);
  } else {
    LOG(WARN) << "Failed to determine element attribute";
  }

  return WD_SUCCESS;
}
예제 #2
0
bool Element::IsSelected() {
  LOG(TRACE) << "Entering Element::IsSelected";

  bool selected(false);
  // The atom is just the definition of an anonymous
  // function: "function() {...}"; Wrap it in another function so we can
  // invoke it with our arguments without polluting the current namespace.
  std::wstring script_source(L"(function() { return (");
  script_source += atoms::asString(atoms::IS_SELECTED);
  script_source += L")})();";

  CComPtr<IHTMLDocument2> doc;
  this->GetContainingDocument(false, &doc);
  Script script_wrapper(doc, script_source, 1);
  script_wrapper.AddArgument(this->element_);
  int status_code = script_wrapper.Execute();

  if (status_code == WD_SUCCESS && script_wrapper.ResultIsBoolean()) {
    selected = script_wrapper.result().boolVal == VARIANT_TRUE;
  } else {
    LOG(WARN) << "Unable to determine is element selected";
  }

  return selected;
}
예제 #3
0
int Element::IsDisplayed(bool* result) {
  LOG(TRACE) << "Entering Element::IsDisplayed";

  int status_code = WD_SUCCESS;

  // The atom is just the definition of an anonymous
  // function: "function() {...}"; Wrap it in another function so we can
  // invoke it with our arguments without polluting the current namespace.
  std::wstring script_source(L"(function() { return (");
  script_source += atoms::asString(atoms::IS_DISPLAYED);
  script_source += L")})();";

  CComPtr<IHTMLDocument2> doc;
  this->GetContainingDocument(false, &doc);
  // N.B., The second argument to the IsDisplayed atom is "ignoreOpacity".
  Script script_wrapper(doc, script_source, 2);
  script_wrapper.AddArgument(this->element_);
  script_wrapper.AddArgument(true);
  status_code = script_wrapper.Execute();

  if (status_code == WD_SUCCESS) {
    *result = script_wrapper.result().boolVal == VARIANT_TRUE;
  } else {
    LOG(WARN) << "Failed to determine is element displayed";
  }

  return status_code;
}
예제 #4
0
int ElementFinder::FindElementsByCssSelector(const IESessionWindow& session, const ElementHandle parent_wrapper, const std::wstring& criteria, Json::Value* found_elements) {
	int result = ENOSUCHELEMENT;

	BrowserHandle browser;
	result = session.GetCurrentBrowser(&browser);
	if (result != SUCCESS) {
		return result;
	}

	std::wstring script_source(L"(function() { return function(){");
	script_source += atoms::SIZZLE;
	script_source += L"\n";
	script_source += L"var root = arguments[1] ? arguments[1] : document.documentElement;";
	script_source += L"if (root['querySelectorAll']) { return root.querySelectorAll(arguments[0]); } ";
	script_source += L"var results = []; Sizzle(arguments[0], root, results);";
	script_source += L"return results;";
	script_source += L"};})();";

	CComPtr<IHTMLDocument2> doc;
	browser->GetDocument(&doc);

	Script script_wrapper(doc, script_source, 2);
	script_wrapper.AddArgument(criteria);
	if (parent_wrapper) {
		// Use a copy for the parent element?
		CComPtr<IHTMLElement> parent(parent_wrapper->element());
		IHTMLElement* parent_element_copy;
		HRESULT hr = parent.CopyTo(&parent_element_copy);
		script_wrapper.AddArgument(parent_element_copy);
	}

	result = script_wrapper.Execute();
	CComVariant snapshot = script_wrapper.result();

	std::wstring get_element_count_script = L"(function(){return function() {return arguments[0].length;}})();";
	Script get_element_count_script_wrapper(doc, get_element_count_script, 1);
	get_element_count_script_wrapper.AddArgument(snapshot);
	result = get_element_count_script_wrapper.Execute();
	if (result == SUCCESS) {
		if (!get_element_count_script_wrapper.ResultIsInteger()) {
			result = EUNEXPECTEDJSERROR;
		} else {
			long length = get_element_count_script_wrapper.result().lVal;
			std::wstring get_next_element_script = L"(function(){return function() {return arguments[0][arguments[1]];}})();";
			for (long i = 0; i < length; ++i) {
				Script get_element_script_wrapper(doc, get_next_element_script, 2);
				get_element_script_wrapper.AddArgument(snapshot);
				get_element_script_wrapper.AddArgument(i);
				result = get_element_script_wrapper.Execute();
				Json::Value json_element;
				get_element_script_wrapper.ConvertResultToJsonValue(session, &json_element);
				found_elements->append(json_element);
			}
		}
	}

	return result;
}
void GetElementTextCommandHandler::ExecuteInternal(
    const IECommandExecutor& executor,
    const ParametersMap& command_parameters,
    Response* response) {
  ParametersMap::const_iterator id_parameter_iterator = command_parameters.find("id");
  if (id_parameter_iterator == command_parameters.end()) {
    response->SetErrorResponse(ERROR_INVALID_ARGUMENT, "Missing parameter in URL: id");
    return;
  } else {
    std::string element_id = id_parameter_iterator->second.asString();

    BrowserHandle browser_wrapper;
    int status_code = executor.GetCurrentBrowser(&browser_wrapper);
    if (status_code != WD_SUCCESS) {
      response->SetErrorResponse(status_code, "Unable to get browser");
      return;
    }

    ElementHandle element_wrapper;
    status_code = this->GetElement(executor, element_id, &element_wrapper);
    if (status_code == WD_SUCCESS) {
      // The atom is just the definition of an anonymous
      // function: "function() {...}"; Wrap it in another function so
      // we can invoke it with our arguments without polluting the
      // current namespace.
      std::wstring script_source = L"(function() { return (";
      script_source += atoms::asString(atoms::GET_TEXT);
      script_source += L")})();";

      CComPtr<IHTMLDocument2> doc;
      browser_wrapper->GetDocument(&doc);
      Script script_wrapper(doc, script_source, 1);
      script_wrapper.AddArgument(element_wrapper->element());
      status_code = script_wrapper.Execute();

      if (status_code == WD_SUCCESS) {
        std::string text = "";
        bool is_null = script_wrapper.ConvertResultToString(&text);
        response->SetSuccessResponse(text);
        return;
      } else {
        response->SetErrorResponse(status_code,
                                    "Unable to get element text");
        return;
      }
    } else {
      response->SetErrorResponse(ERROR_STALE_ELEMENT_REFERENCE, "Element is no longer valid");
      return;
    }
  }
}
예제 #6
0
int BrowserWrapper::DeleteCookie(const std::wstring& cookie_name) {
	// Construct the delete cookie script
	std::wstring script;
	for (int i = 0; DELETECOOKIES[i]; i++) {
		script += DELETECOOKIES[i];
	}

	CComPtr<IHTMLDocument2> doc;
	this->GetDocument(&doc);
	ScriptWrapper script_wrapper(doc, script, 1);
	script_wrapper.AddArgument(cookie_name);
	int status_code = script_wrapper.Execute();
	return status_code;
}
예제 #7
0
int ElementFinder::InjectXPathEngine(BrowserHandle browser_wrapper) {
	// Inject the XPath engine
	std::wstring script_source;
	for (int i = 0; XPATHJS[i]; i++) {
		script_source += XPATHJS[i];
	}

	CComPtr<IHTMLDocument2> doc;
	browser_wrapper->GetDocument(&doc);
	Script script_wrapper(doc, script_source, 0);
	int status_code = script_wrapper.Execute();

	return status_code;
}
예제 #8
0
int ElementFinder::FindElementUsingSizzle(const IECommandExecutor& executor,
                                          const ElementHandle parent_wrapper,
                                          const std::wstring& criteria,
                                          Json::Value* found_element) {
  LOG(TRACE) << "Entering ElementFinder::FindElementUsingSizzle";

  int result;

  BrowserHandle browser;
  result = executor.GetCurrentBrowser(&browser);
  if (result != WD_SUCCESS) {
    LOG(WARN) << "Unable to get browser";
    return result;
  }

  std::wstring script_source(L"(function() { return function(){ if (!window.Sizzle) {");
  script_source += atoms::asString(atoms::SIZZLE);
  script_source += L"}\n";
  script_source += L"var root = arguments[1] ? arguments[1] : document.documentElement;";
  script_source += L"if (root['querySelector']) { return root.querySelector(arguments[0]); } ";
  script_source += L"var results = []; Sizzle(arguments[0], root, results);";
  script_source += L"return results.length > 0 ? results[0] : null;";
  script_source += L"};})();";

  CComPtr<IHTMLDocument2> doc;
  browser->GetDocument(&doc);
  Script script_wrapper(doc, script_source, 2);
  script_wrapper.AddArgument(criteria);
  if (parent_wrapper) {
    CComPtr<IHTMLElement> parent(parent_wrapper->element());
    script_wrapper.AddArgument(parent);
  }
  result = script_wrapper.Execute();

  if (result == WD_SUCCESS) {
    if (!script_wrapper.ResultIsElement()) {
      LOG(WARN) << "Found result is not element";
      result = ENOSUCHELEMENT;
    } else {
      result = script_wrapper.ConvertResultToJsonValue(executor,
                                                       found_element);
    }
  } else {
    LOG(WARN) << "Unable to find elements";
    result = ENOSUCHELEMENT;
  }

  return result;
}
int DocumentHost::DeleteCookie(const std::string& cookie_name) {
  LOG(TRACE) << "Entering DocumentHost::DeleteCookie";

  // Construct the delete cookie script
  std::wstring script_source;
  for (int i = 0; DELETECOOKIES[i]; i++) {
    script_source += DELETECOOKIES[i];
  }

  CComPtr<IHTMLDocument2> doc;
  this->GetDocument(&doc);
  Script script_wrapper(doc, script_source, 1);
  script_wrapper.AddArgument(cookie_name);
  int status_code = script_wrapper.Execute();
  return status_code;
}
예제 #10
0
bool Element::IsHiddenByOverflow() {
  LOG(TRACE) << "Entering Element::IsHiddenByOverflow";

  bool isOverflow = false;

  // what is more correct: this code or JS dom.bot.isShown.isOverflowHiding ?
  // Use JavaScript for this rather than COM calls to avoid dependency
  // on the IHTMLWindow7 interface, which is IE9-specific.
  std::wstring script_source = L"(function() { return function(){";
  script_source += L"var e = arguments[0];";
  script_source += L"var p = e.parentNode;";
  //Note: This logic duplicates Element::GetClickPoint
  script_source += L"var x = e.offsetLeft + (e.clientWidth / 2);";
  script_source += L"var y = e.offsetTop + (e.clientHeight / 2);";
  script_source += L"var s = window.getComputedStyle ? window.getComputedStyle(p, null) : p.currentStyle;";
  //Note: In the case that the parent has overflow=hidden, and the element is out of sight,
  //this will force the IEDriver to scroll the element in to view.  This is a bug.
  //Note: If we reach the document while walking up the DOM tree, we know we've not
  //encountered an element with the style that would indicate the element is hidden by overflow.
  script_source += L"while (p != null && s != null && s.overflow && s.overflow != 'auto' && s.overflow != 'scroll' && s.overflow != 'hidden') {";
  script_source += L"  p = p.parentNode;";
  script_source += L"  if (p === document) {";
  script_source += L"    return false;";
  script_source += L"  } else {";
  script_source += L"    s = window.getComputedStyle ? window.getComputedStyle(p, null) : p.currentStyle;";
  script_source += L"  }";
  script_source += L"}";
  script_source += L"var containerTop = p.scrollTop;";
  script_source += L"var containerLeft = p.scrollLeft;";
  script_source += L"return p != null && ";
  script_source += L"(x < containerLeft || x > containerLeft + p.clientWidth || ";
  script_source += L"y < containerTop || y > containerTop + p.clientHeight);";
  script_source += L"};})();";

  CComPtr<IHTMLDocument2> doc;
  this->GetContainingDocument(false, &doc);
  Script script_wrapper(doc, script_source, 1);
  script_wrapper.AddArgument(this->element_);
  int status_code = script_wrapper.Execute();
  if (status_code == SUCCESS) {
    isOverflow = script_wrapper.result().boolVal == VARIANT_TRUE;
  } else {
    LOG(WARN) << "Unable to determine is element hidden by overflow";
  }

  return isOverflow;
}
예제 #11
0
int ElementFinder::FindElementByXPath(const IESessionWindow& session, const ElementHandle parent_wrapper, const std::wstring& criteria, Json::Value* found_element) {
	int result = ENOSUCHELEMENT;

	BrowserHandle browser;
	result = session.GetCurrentBrowser(&browser);
	if (result != SUCCESS) {
		return result;
	}

	result = this->InjectXPathEngine(browser);
	// TODO(simon): Why does the injecting sometimes fail?
	if (result != SUCCESS) {
		return result;
	}

	// Call it
	std::wstring query;
	if (parent_wrapper) {
		query += L"(function() { return function(){var res = document.__webdriver_evaluate(arguments[0], arguments[1], null, 7, null); return res.snapshotItem(0) ;};})();";
	} else {
		query += L"(function() { return function(){var res = document.__webdriver_evaluate(arguments[0], document, null, 7, null); return res.snapshotLength != 0 ? res.snapshotItem(0) : undefined ;};})();";
	}

	CComPtr<IHTMLDocument2> doc;
	browser->GetDocument(&doc);
	Script script_wrapper(doc, query, 2);
	script_wrapper.AddArgument(criteria);
	if (parent_wrapper) {
		CComPtr<IHTMLElement> parent(parent_wrapper->element());
		IHTMLElement* parent_element_copy;
		HRESULT hr = parent.CopyTo(&parent_element_copy);
		script_wrapper.AddArgument(parent_element_copy);
	}
	result = script_wrapper.Execute();

	if (result == SUCCESS) {
		if (!script_wrapper.ResultIsElement()) {
			result = ENOSUCHELEMENT;
		} else {
			result = script_wrapper.ConvertResultToJsonValue(session, found_element);
		}
	}

	return result;
}
예제 #12
0
int ElementFinder::FindElement(const IESessionWindow& session, const ElementHandle parent_wrapper, const std::wstring& mechanism, const std::wstring& criteria, Json::Value* found_element) {
	BrowserHandle browser;
	int status_code = session.GetCurrentBrowser(&browser);
	if (status_code == SUCCESS) {
		if (mechanism == L"css") {
			return this->FindElementByCssSelector(session, parent_wrapper, criteria, found_element);
		} else if (mechanism == L"xpath") {
			return this->FindElementByXPath(session, parent_wrapper, criteria, found_element);
		} else {
			std::wstring criteria_object_script = L"(function() { return function(){ return  { \"" + mechanism + L"\" : \"" + criteria + L"\" }; };})();";
			CComPtr<IHTMLDocument2> doc;
			browser->GetDocument(&doc);

			Script criteria_wrapper(doc, criteria_object_script, 0);
			status_code = criteria_wrapper.Execute();
			if (status_code == SUCCESS) {
				CComVariant criteria_object;
				HRESULT hr = ::VariantCopy(&criteria_object, &criteria_wrapper.result());

				// The atom is just the definition of an anonymous
				// function: "function() {...}"; Wrap it in another function so we can
				// invoke it with our arguments without polluting the current namespace.
				std::wstring script_source(L"(function() { return (");
				script_source += atoms::FIND_ELEMENT;
				script_source += L")})();";

				Script script_wrapper(doc, script_source, 2);
				script_wrapper.AddArgument(criteria_object);
				if (parent_wrapper) {
					script_wrapper.AddArgument(parent_wrapper->element());
				}

				status_code = script_wrapper.Execute();
				if (status_code == SUCCESS && script_wrapper.ResultIsElement()) {
					script_wrapper.ConvertResultToJsonValue(session, found_element);
				} else {
					status_code = ENOSUCHELEMENT;
				}
			} else {
				status_code = ENOSUCHELEMENT;
			}
		}
	}
	return status_code;
}
예제 #13
0
bool ElementFinder::HasNativeCssSelectorEngine(const IECommandExecutor& executor) {
  LOG(TRACE) << "Entering ElementFinder::HasNativeCssSelectorEngine";

  BrowserHandle browser;
  executor.GetCurrentBrowser(&browser);

  std::wstring script_source(L"(function() { return function(){");
  script_source += L"var root = document.documentElement;";
  script_source += L"if (root['querySelectorAll']) { return true; } ";
  script_source += L"return false;";
  script_source += L"};})();";

  CComPtr<IHTMLDocument2> doc;
  browser->GetDocument(&doc);

  Script script_wrapper(doc, script_source, 0);
  script_wrapper.Execute();
  return script_wrapper.result().boolVal == VARIANT_TRUE;
}
예제 #14
0
int ElementFinder::FindElementByCssSelector(const IESessionWindow& session, const ElementHandle parent_wrapper, const std::wstring& criteria, Json::Value* found_element) {
	int result = ENOSUCHELEMENT;

	BrowserHandle browser;
	result = session.GetCurrentBrowser(&browser);
	if (result != SUCCESS) {
		return result;
	}

	std::wstring script_source(L"(function() { return function(){");
	script_source += atoms::SIZZLE;
	script_source += L"\n";
	script_source += L"var root = arguments[1] ? arguments[1] : document.documentElement;";
	script_source += L"if (root['querySelector']) { return root.querySelector(arguments[0]); } ";
	script_source += L"var results = []; Sizzle(arguments[0], root, results);";
	script_source += L"return results.length > 0 ? results[0] : null;";
	script_source += L"};})();";

	CComPtr<IHTMLDocument2> doc;
	browser->GetDocument(&doc);
	Script script_wrapper(doc, script_source, 2);
	script_wrapper.AddArgument(criteria);
	if (parent_wrapper) {
		CComPtr<IHTMLElement> parent(parent_wrapper->element());
		IHTMLElement* parent_element_copy;
		HRESULT hr = parent.CopyTo(&parent_element_copy);
		script_wrapper.AddArgument(parent_element_copy);
	}
	result = script_wrapper.Execute();

	if (result == SUCCESS) {
		if (!script_wrapper.ResultIsElement()) {
			result = ENOSUCHELEMENT;
		} else {
			result = script_wrapper.ConvertResultToJsonValue(session, found_element);
		}
	}

	return result;
}
예제 #15
0
bool Element::IsHiddenByOverflow() {
  LOG(TRACE) << "Entering Element::IsHiddenByOverflow";

  bool isOverflow = false;

  std::wstring script_source(L"(function() { return (");
  script_source += atoms::asString(atoms::IS_IN_PARENT_OVERFLOW);
  script_source += L")})();";

  CComPtr<IHTMLDocument2> doc;
  this->GetContainingDocument(false, &doc);
  Script script_wrapper(doc, script_source, 1);
  script_wrapper.AddArgument(this->element_);
  int status_code = script_wrapper.Execute();
  if (status_code == WD_SUCCESS) {
    isOverflow = script_wrapper.result().boolVal == VARIANT_TRUE;
  } else {
    LOG(WARN) << "Unable to determine is element hidden by overflow";
  }

  return isOverflow;
}
예제 #16
0
int ClickElementCommandHandler::ExecuteAtom(
    const std::wstring& atom_script_source,
    BrowserHandle browser_wrapper,
    ElementHandle element_wrapper,
    std::string* error_msg) {
  CComPtr<IHTMLDocument2> doc;
  browser_wrapper->GetDocument(&doc);
  Script script_wrapper(doc, atom_script_source, 1);
  script_wrapper.AddArgument(element_wrapper);
  int status_code = script_wrapper.ExecuteAsync(ASYNC_SCRIPT_EXECUTION_TIMEOUT_IN_MILLISECONDS);
  if (status_code != WD_SUCCESS) {
    if (script_wrapper.ResultIsString()) {
      std::wstring error = script_wrapper.result().bstrVal;
      *error_msg = StringUtilities::ToString(error);
    } else {
      std::string error = "Executing JavaScript click function returned an";
      error.append(" unexpected error, but no error could be returned from");
      error.append(" Internet Explorer's JavaScript engine.");
      *error_msg = error;
    }
  }
  return status_code;
}
예제 #17
0
int ElementFinder::FindElements(const IECommandExecutor& executor,
                                const ElementHandle parent_wrapper,
                                const std::wstring& mechanism,
                                const std::wstring& criteria,
                                Json::Value* found_elements) {
  LOG(TRACE) << "Entering ElementFinder::FindElements";

  BrowserHandle browser;
  int status_code = executor.GetCurrentBrowser(&browser);
  if (status_code == WD_SUCCESS) {
    if (mechanism == L"css") {
      if (!this->HasNativeCssSelectorEngine(executor)) {
        LOG(DEBUG) << "Element location strategy is CSS selectors, but "
                   << "document does not support CSS selectors. Falling back "
                   << "to using the Sizzle JavaScript CSS selector engine.";
        return this->FindElementsUsingSizzle(executor,
                                             parent_wrapper,
                                             criteria,
                                             found_elements);
      }
    }

    LOG(DEBUG) << "Using FindElements atom to locate element having "
               << LOGWSTRING(mechanism) << " = "
               << LOGWSTRING(criteria);
    CComPtr<IHTMLDocument2> doc;
    browser->GetDocument(&doc);

    std::wstring script_source(L"(function() { return (");
    script_source += atoms::asString(atoms::FIND_ELEMENTS);
    script_source += L")})();";

    Script script_wrapper(doc, script_source, 3);
    script_wrapper.AddArgument(mechanism);
    script_wrapper.AddArgument(criteria);
    if (parent_wrapper) {
      script_wrapper.AddArgument(parent_wrapper->element());
    }

    status_code = script_wrapper.Execute();
    if (status_code == WD_SUCCESS) {
      Json::Value atom_result;
      script_wrapper.ConvertResultToJsonValue(executor, &atom_result);
      int atom_status_code = atom_result["status"].asInt();
      Json::Value atom_value = atom_result["value"];
      status_code = atom_status_code;
      *found_elements = atom_result["value"];
    } else {
      // Hitting a JavaScript error with the atom is an unrecoverable
      // error. The most common case of this for IE is when there is a
      // page refresh, navigation, or similar, and the driver is polling
      // for element presence. The calling code can't do anything about
      // it, so we might as well just log and return In the common case,
      // this means that the error will be transitory, and will sort
      // itself out once the DOM returns to normal after the page transition
      // is completed.
      LOG(WARN) << "A JavaScript error was encountered executing the findElements atom.";
    }
  } else {
    LOG(WARN) << "Unable to get browser";
  }
  return status_code;
}
예제 #18
0
int ElementFinder::FindElementsUsingSizzle(const IECommandExecutor& executor,
                                           const ElementHandle parent_wrapper,
                                           const std::wstring& criteria,
                                           Json::Value* found_elements) {
  LOG(TRACE) << "Entering ElementFinder::FindElementsUsingSizzle";

  int result;

  if (criteria == L"") {
    // Apparently, Sizzle will happily return an empty array for an empty
    // string as the selector. We do not want this.
    return ENOSUCHELEMENT;
  }

  BrowserHandle browser;
  result = executor.GetCurrentBrowser(&browser);
  if (result != WD_SUCCESS) {
    LOG(WARN) << "Unable to get browser";
    return result;
  }

  std::wstring script_source(L"(function() { return function(){ if (!window.Sizzle) {");
  script_source += atoms::asString(atoms::SIZZLE);
  script_source += L"}\n";
  script_source += L"var root = arguments[1] ? arguments[1] : document.documentElement;";
  script_source += L"if (root['querySelectorAll']) { return root.querySelectorAll(arguments[0]); } ";
  script_source += L"var results = []; try { Sizzle(arguments[0], root, results); } catch(ex) { results = null; }";
  script_source += L"return results;";
  script_source += L"};})();";

  CComPtr<IHTMLDocument2> doc;
  browser->GetDocument(&doc);

  Script script_wrapper(doc, script_source, 2);
  script_wrapper.AddArgument(criteria);
  if (parent_wrapper) {
    // Use a copy for the parent element?
    CComPtr<IHTMLElement> parent(parent_wrapper->element());
    script_wrapper.AddArgument(parent);
  }

  result = script_wrapper.Execute();
  if (result == WD_SUCCESS) {
    CComVariant snapshot = script_wrapper.result();
    if (snapshot.vt == VT_NULL || snapshot.vt == VT_EMPTY) {
      // We explicitly caught an error from Sizzle. Return ENOSUCHELEMENT.
      return ENOSUCHELEMENT;
    }
    std::wstring get_element_count_script = L"(function(){return function() {return arguments[0].length;}})();";
    Script get_element_count_script_wrapper(doc, get_element_count_script, 1);
    get_element_count_script_wrapper.AddArgument(snapshot);
    result = get_element_count_script_wrapper.Execute();
    if (result == WD_SUCCESS) {
      *found_elements = Json::Value(Json::arrayValue);
      if (!get_element_count_script_wrapper.ResultIsInteger()) {
        LOG(WARN) << "Found elements count is not integer";
        result = EUNEXPECTEDJSERROR;
      } else {
        long length = get_element_count_script_wrapper.result().lVal;
        std::wstring get_next_element_script = L"(function(){return function() {return arguments[0][arguments[1]];}})();";
        for (long i = 0; i < length; ++i) {
          Script get_element_script_wrapper(doc, get_next_element_script, 2);
          get_element_script_wrapper.AddArgument(snapshot);
          get_element_script_wrapper.AddArgument(i);
          result = get_element_script_wrapper.Execute();
          if (result == WD_SUCCESS) {
            Json::Value json_element;
            get_element_script_wrapper.ConvertResultToJsonValue(executor,
                                                            &json_element);
            found_elements->append(json_element);
          } else {
            LOG(WARN) << "Unable to get " << i << " found element";
          }
        }
      }
    } else {
      LOG(WARN) << "Unable to get count of found elements";
      result = EUNEXPECTEDJSERROR;
    }

  } else {
    LOG(WARN) << "Execution returned error";
  }

  return result;
}
예제 #19
0
int ElementFinder::FindElement(const IECommandExecutor& executor,
                               const ElementHandle parent_wrapper,
                               const std::wstring& mechanism,
                               const std::wstring& criteria,
                               Json::Value* found_element) {
  LOG(TRACE) << "Entering ElementFinder::FindElement";

  BrowserHandle browser;
  int status_code = executor.GetCurrentBrowser(&browser);
  if (status_code == WD_SUCCESS) {
    if (mechanism == L"css") {
      if (!this->HasNativeCssSelectorEngine(executor)) {
        LOG(DEBUG) << "Element location strategy is CSS selectors, but "
                   << "document does not support CSS selectors. Falling back "
                   << "to using the Sizzle JavaScript CSS selector engine.";
        return this->FindElementUsingSizzle(executor,
                                            parent_wrapper,
                                            criteria,
                                            found_element);
      }
    }

    LOG(DEBUG) << L"Using FindElement atom to locate element having "
               << LOGWSTRING(mechanism) << " = "
               << LOGWSTRING(criteria);
    std::wstring sanitized_criteria = criteria;
    this->SanitizeCriteria(mechanism, &sanitized_criteria);
    std::wstring criteria_object_script = L"(function() { return function(){ return  { \"" + 
                                          mechanism + 
                                          L"\" : \"" +
                                          sanitized_criteria + L"\" }; };})();";
    CComPtr<IHTMLDocument2> doc;
    browser->GetDocument(&doc);

    Script criteria_wrapper(doc, criteria_object_script, 0);
    status_code = criteria_wrapper.Execute();
    if (status_code == WD_SUCCESS) {
      CComVariant criteria_object;
      criteria_object.Copy(&criteria_wrapper.result());

      // The atom is just the definition of an anonymous
      // function: "function() {...}"; Wrap it in another function so we can
      // invoke it with our arguments without polluting the current namespace.
      std::wstring script_source(L"(function() { return (");
      script_source += atoms::asString(atoms::FIND_ELEMENT);
      script_source += L")})();";

      Script script_wrapper(doc, script_source, 2);
      script_wrapper.AddArgument(criteria_object);
      if (parent_wrapper) {
        script_wrapper.AddArgument(parent_wrapper->element());
      }

      status_code = script_wrapper.Execute();
      if (status_code == WD_SUCCESS) {
        if (script_wrapper.ResultIsElement()) {
          script_wrapper.ConvertResultToJsonValue(executor, found_element);
        } else {
          LOG(WARN) << "Unable to find element by mechanism "
                    << LOGWSTRING(mechanism) << " and criteria " 
                    << LOGWSTRING(sanitized_criteria);
          status_code = ENOSUCHELEMENT;
        }
      } else {
        // An error in the execution of the FindElement atom for XPath is assumed
        // to be a syntactically invalid XPath.
        if (mechanism == L"xpath") {
          LOG(WARN) << "Attempted to find element using invalid xpath: "
                    << LOGWSTRING(sanitized_criteria);
          status_code = EINVALIDSELECTOR;
        } else {
          LOG(WARN) << "Unexpected error attempting to find element by mechanism "
                    << LOGWSTRING(mechanism) << " with criteria "
                    << LOGWSTRING(sanitized_criteria);
          status_code = ENOSUCHELEMENT;
        }
      }
    } else {
      LOG(WARN) << "Unable to create criteria object for mechanism "
                << LOGWSTRING(mechanism) << " and criteria " 
                << LOGWSTRING(sanitized_criteria);
      status_code = ENOSUCHELEMENT;
    }
  } else {
    LOG(WARN) << "Unable to get browser";
  }
  return status_code;
}
예제 #20
0
bool Element::GetFrameDetails(LocationInfo* location, std::vector<LocationInfo>* frame_locations) {
  LOG(TRACE) << "Entering Element::GetFrameDetails";

  CComPtr<IHTMLDocument2> owner_doc;
  int status_code = this->GetContainingDocument(true, &owner_doc);
  if (status_code != WD_SUCCESS) {
    LOG(WARN) << "Unable to get containing document";
    return false;
  }

  CComPtr<IHTMLWindow2> owner_doc_window;
  HRESULT hr = owner_doc->get_parentWindow(&owner_doc_window);
  if (!owner_doc_window) {
    LOG(WARN) << "Unable to get parent window, call to IHTMLDocument2::get_parentWindow failed";
    return false;
  }

  // Get the parent window to the current window, where "current window" is
  // the window containing the parent document of this element. If that parent
  // window exists, and it is not the same as the current window, we assume
  // this element exists inside a frame or iframe. If it is in a frame, get
  // the parent document containing the frame, so we can get the information
  // about the frame or iframe element hosting the document of this element.
  CComPtr<IHTMLWindow2> parent_window;
  hr = owner_doc_window->get_parent(&parent_window);
  if (parent_window && !owner_doc_window.IsEqualObject(parent_window)) {
    LOG(DEBUG) << "Element is in a frame.";
    CComPtr<IHTMLDocument2> parent_doc;
    status_code = this->GetDocumentFromWindow(parent_window, &parent_doc);

    CComPtr<IHTMLFramesCollection2> frames;
    hr = parent_doc->get_frames(&frames);

    long frame_count(0);
    hr = frames->get_length(&frame_count);
    CComVariant index;
    index.vt = VT_I4;
    for (long i = 0; i < frame_count; ++i) {
      // See if the document in each frame is this element's 
      // owner document.
      index.lVal = i;
      CComVariant result;
      hr = frames->item(&index, &result);
      CComPtr<IHTMLWindow2> frame_window;
      result.pdispVal->QueryInterface<IHTMLWindow2>(&frame_window);
      if (!frame_window) {
        // Frame is not an HTML frame.
        continue;
      }

      CComPtr<IHTMLDocument2> frame_doc;
      status_code = this->GetDocumentFromWindow(frame_window, &frame_doc);

      if (frame_doc.IsEqualObject(owner_doc)) {
        // The document in this frame *is* this element's owner
        // document. Get the frameElement property of the document's
        // containing window (which is itself an HTML element, either
        // a frame or an iframe). Then get the x and y coordinates of
        // that frame element.
        // N.B. We must use JavaScript here, as directly using
        // IHTMLWindow4.get_frameElement() returns E_NOINTERFACE under
        // some circumstances.
        LOG(DEBUG) << "Located host frame. Attempting to get hosting element";
        std::wstring script_source = L"(function(){ return function() { return arguments[0].frameElement };})();";
        Script script_wrapper(frame_doc, script_source, 1);
        CComVariant window_variant(frame_window);
        script_wrapper.AddArgument(window_variant);
        status_code = script_wrapper.Execute();
        CComPtr<IHTMLFrameBase> frame_base;
        if (status_code == WD_SUCCESS) {
          hr = script_wrapper.result().pdispVal->QueryInterface<IHTMLFrameBase>(&frame_base);
          if (FAILED(hr)) {
            LOG(WARN) << "Found the frame element, but could not QueryInterface to IHTMLFrameBase.";
          }
        } else {
          // Can't get the frameElement property, likely because the frames are from different
          // domains. So start at the parent document, and use getElementsByTagName to retrieve
          // all of the iframe elements (if there are no iframe elements, get the frame elements)
          // **** BIG HUGE ASSUMPTION!!! ****
          // The index of the frame from the document.frames collection will correspond to the 
          // index into the collection of iframe/frame elements returned by getElementsByTagName.
          LOG(WARN) << "Attempting to get frameElement via JavaScript failed. "
                    << "This usually means the frame is in a different domain than the parent frame. "
                    << "Browser security against cross-site scripting attacks will not allow this. "
                    << "Attempting alternative method.";
          long collection_count = 0;
          CComPtr<IDispatch> element_dispatch;
          CComPtr<IHTMLDocument3> doc;
          parent_doc->QueryInterface<IHTMLDocument3>(&doc);
          if (doc) {
            LOG(DEBUG) << "Looking for <iframe> elements in parent document.";
            CComBSTR iframe_tag_name = L"iframe";
            CComPtr<IHTMLElementCollection> iframe_collection;
            hr = doc->getElementsByTagName(iframe_tag_name, &iframe_collection);
            hr = iframe_collection->get_length(&collection_count);
            if (collection_count != 0) {
              if (collection_count > index.lVal) {
                LOG(DEBUG) << "Found <iframe> elements in parent document, retrieving element" << index.lVal << ".";
                hr = iframe_collection->item(index, index, &element_dispatch);
                hr = element_dispatch->QueryInterface<IHTMLFrameBase>(&frame_base);
              }
            } else {
              LOG(DEBUG) << "No <iframe> elements, looking for <frame> elements in parent document.";
              CComBSTR frame_tag_name = L"frame";
              CComPtr<IHTMLElementCollection> frame_collection;
              hr = doc->getElementsByTagName(frame_tag_name, &frame_collection);
              hr = frame_collection->get_length(&collection_count);
              if (collection_count > index.lVal) {
                LOG(DEBUG) << "Found <frame> elements in parent document, retrieving element" << index.lVal << ".";
                hr = frame_collection->item(index, index, &element_dispatch);
                hr = element_dispatch->QueryInterface<IHTMLFrameBase>(&frame_base);
              }
            }
          } else {
            LOG(WARN) << "QueryInterface of parent document to IHTMLDocument3 failed.";
          }
        }

        if (frame_base) {
          LOG(DEBUG) << "Successfully found frame hosting element";
          LocationInfo frame_doc_info;
          bool doc_dimensions_success = DocumentHost::GetDocumentDimensions(
              frame_doc,
              &frame_doc_info);

          // Wrap the element so we can find its location. Note that
          // GetLocation() may recursively call into this method.
          CComPtr<IHTMLElement> frame_element;
          frame_base->QueryInterface<IHTMLElement>(&frame_element);
          Element element_wrapper(frame_element, this->containing_window_handle_);
          CComPtr<IHTMLStyle> style;
          frame_element->get_style(&style);

          LocationInfo frame_location = {};
          status_code = element_wrapper.GetLocation(&frame_location,
                                                    frame_locations);

          // Take the border of the frame element into account.
          // N.B. We don't have to do this for non-frame elements,
          // because the border is part of the hit-test region. For
          // finding offsets to get absolute position of elements 
          // within frames, the origin of the frame document is offset
          // by the border width.
          CComPtr<IHTMLElement2> border_width_element;
          frame_element->QueryInterface<IHTMLElement2>(&border_width_element);
          long left_border_width = 0;
          border_width_element->get_clientLeft(&left_border_width);
          long top_border_width = 0;
          border_width_element->get_clientTop(&top_border_width);

          if (status_code == WD_SUCCESS) {
            // Take into account the presence of scrollbars in the frame.
            long frame_element_width = frame_location.width;
            long frame_element_height = frame_location.height;
            if (doc_dimensions_success) {
              if (frame_doc_info.height > frame_element_height) {
                int horizontal_scrollbar_height = ::GetSystemMetrics(SM_CYHSCROLL);
                frame_element_height -= horizontal_scrollbar_height;
              }
              if (frame_doc_info.width > frame_element_width) {
                int vertical_scrollbar_width = ::GetSystemMetrics(SM_CXVSCROLL);
                frame_element_width -= vertical_scrollbar_width;
              }
            }
            location->x = frame_location.x + left_border_width;
            location->y = frame_location.y + top_border_width;
            location->width = frame_element_width;
            location->height = frame_element_height;
          }
          return true;
        }
      }
    }
  }

  // If we reach here, the element isn't in a frame/iframe.
  return false;
}
예제 #21
0
int Element::GetFrameOffset(long* x, long* y) {
  LOG(TRACE) << "Entering Element::GetFrameOffset";

  CComPtr<IHTMLDocument2> owner_doc;
  int status_code = this->GetContainingDocument(true, &owner_doc);
  if (status_code != SUCCESS) {
    LOG(WARN) << "Unable to get containing document";
    return status_code;
  }

  CComPtr<IHTMLWindow2> owner_doc_window;
  HRESULT hr = owner_doc->get_parentWindow(&owner_doc_window);
  if (!owner_doc_window) {
    LOG(WARN) << "Unable to get parent window, call to IHTMLDocument2::get_parentWindow failed";
    return ENOSUCHDOCUMENT;
  }

  CComPtr<IHTMLWindow2> parent_window;
  hr = owner_doc_window->get_parent(&parent_window);
  if (parent_window && !owner_doc_window.IsEqualObject(parent_window)) {
    CComPtr<IHTMLDocument2> parent_doc;
    status_code = this->GetParentDocument(parent_window, &parent_doc);

    CComPtr<IHTMLFramesCollection2> frames;
    hr = parent_doc->get_frames(&frames);

    long frame_count(0);
    hr = frames->get_length(&frame_count);
    CComVariant index;
    index.vt = VT_I4;
    for (long i = 0; i < frame_count; ++i) {
      // See if the document in each frame is this element's 
      // owner document.
      index.lVal = i;
      CComVariant result;
      hr = frames->item(&index, &result);
      CComQIPtr<IHTMLWindow2> frame_window(result.pdispVal);
      if (!frame_window) {
        // Frame is not an HTML frame.
        continue;
      }

      CComPtr<IHTMLDocument2> frame_doc;
      hr = frame_window->get_document(&frame_doc);

      if (frame_doc.IsEqualObject(owner_doc)) {
        // The document in this frame *is* this element's owner
        // document. Get the frameElement property of the document's
        // containing window (which is itself an HTML element, either
        // a frame or an iframe). Then get the x and y coordinates of
        // that frame element.
        std::wstring script_source = L"(function(){ return function() { return arguments[0].frameElement };})();";
        Script script_wrapper(frame_doc, script_source, 1);
        CComVariant window_variant(frame_window);
        script_wrapper.AddArgument(window_variant);
        script_wrapper.Execute();
        CComQIPtr<IHTMLElement> frame_element(script_wrapper.result().pdispVal);

        // Wrap the element so we can find its location.
        Element element_wrapper(frame_element, this->containing_window_handle_);
        long frame_x, frame_y, frame_width, frame_height;
        status_code = element_wrapper.GetLocation(&frame_x,
                                                  &frame_y,
                                                  &frame_width,
                                                  &frame_height);
        if (status_code == SUCCESS) {
          *x = frame_x;
          *y = frame_y;
        }
        break;
      }
    }
  }

  return SUCCESS;
}
예제 #22
0
int ElementFinder::FindElements(const IECommandExecutor& executor,
                                const ElementHandle parent_wrapper,
                                const std::wstring& mechanism,
                                const std::wstring& criteria,
                                Json::Value* found_elements) {
  LOG(TRACE) << "Entering ElementFinder::FindElements";

  BrowserHandle browser;
  int status_code = executor.GetCurrentBrowser(&browser);
  if (status_code == WD_SUCCESS) {
    if (mechanism == L"css") {
      if (!this->HasNativeCssSelectorEngine(executor)) {
        LOG(DEBUG) << "Element location strategy is CSS selectors, but "
                   << "document does not support CSS selectors. Falling back "
                   << "to using the Sizzle JavaScript CSS selector engine.";
        return this->FindElementsUsingSizzle(executor,
                                             parent_wrapper,
                                             criteria,
                                             found_elements);
      }
    }

    LOG(DEBUG) << "Using FindElements atom to locate element having "
               << LOGWSTRING(mechanism) << " = "
               << LOGWSTRING(criteria);
    CComPtr<IHTMLDocument2> doc;
    browser->GetDocument(&doc);

    std::wstring script_source(L"(function() { return (");
    script_source += atoms::asString(atoms::FIND_ELEMENTS);
    script_source += L")})();";

    Script script_wrapper(doc, script_source, 3);
    script_wrapper.AddArgument(mechanism);
    script_wrapper.AddArgument(criteria);
    if (parent_wrapper) {
      script_wrapper.AddArgument(parent_wrapper->element());
    }

    status_code = script_wrapper.Execute();
    if (status_code == WD_SUCCESS) {
      if (script_wrapper.ResultIsArray() || 
          script_wrapper.ResultIsElementCollection()) {
        script_wrapper.ConvertResultToJsonValue(executor, found_elements);
      } else {
        LOG(WARN) << "Returned value is not an array or element collection";
        status_code = ENOSUCHELEMENT;
      }
    } else {
      // An error in the execution of the FindElement atom for XPath is assumed
      // to be a syntactically invalid XPath.
      if (mechanism == L"xpath") {
        LOG(WARN) << "Attempted to find elements using invalid xpath: "
                  << LOGWSTRING(criteria);
        status_code = EINVALIDSELECTOR;
      } else {
        LOG(WARN) << "Unexpected error attempting to find element by mechanism "
                  << LOGWSTRING(mechanism) << " and criteria "
                  << LOGWSTRING(criteria);
        status_code = ENOSUCHELEMENT;
      }
    }
  } else {
    LOG(WARN) << "Unable to get browser";
  }
  return status_code;
}
예제 #23
0
int ElementFinder::FindElementsByXPath(const IESessionWindow& session, const ElementHandle parent_wrapper, const std::wstring& criteria, Json::Value* found_elements) {
	int result = ENOSUCHELEMENT;

	BrowserHandle browser;
	result = session.GetCurrentBrowser(&browser);
	if (result != SUCCESS) {
		return result;
	}
	result = this->InjectXPathEngine(browser);
	// TODO(simon): Why does the injecting sometimes fail?
	if (result != SUCCESS) {
		return result;
	}

	// Call it
	std::wstring query;
	if (parent_wrapper) {
		query += L"(function() { return function() {var res = document.__webdriver_evaluate(arguments[0], arguments[1], null, 7, null); return res;};})();";
	} else {
		query += L"(function() { return function() {var res = document.__webdriver_evaluate(arguments[0], document, null, 7, null); return res;};})();";
	}

	CComPtr<IHTMLDocument2> doc;
	browser->GetDocument(&doc);

	Script script_wrapper(doc, query, 2);
	script_wrapper.AddArgument(criteria);
	if (parent_wrapper) {
		// Use a copy for the parent element?
		CComPtr<IHTMLElement> parent(parent_wrapper->element());
		IHTMLElement* parent_element_copy;
		HRESULT hr = parent.CopyTo(&parent_element_copy);
		script_wrapper.AddArgument(parent_element_copy);
	}

	result = script_wrapper.Execute();
	CComVariant snapshot = script_wrapper.result();

	std::wstring get_element_count_script = L"(function(){return function() {return arguments[0].snapshotLength;}})();";
	Script get_element_count_script_wrapper(doc, get_element_count_script, 1);
	get_element_count_script_wrapper.AddArgument(snapshot);
	result = get_element_count_script_wrapper.Execute();
	if (result == SUCCESS) {
		if (!get_element_count_script_wrapper.ResultIsInteger()) {
			result = EUNEXPECTEDJSERROR;
		} else {
			long length = get_element_count_script_wrapper.result().lVal;
			std::wstring get_next_element_script(L"(function(){return function() {return arguments[0].iterateNext();}})();");
			for (long i = 0; i < length; ++i) {
				Script get_element_script_wrapper(doc, get_next_element_script, 2);
				get_element_script_wrapper.AddArgument(snapshot);
				get_element_script_wrapper.AddArgument(i);
				result = get_element_script_wrapper.Execute();
				Json::Value json_element;
				get_element_script_wrapper.ConvertResultToJsonValue(session, &json_element);
				found_elements->append(json_element);
			}
		}
	}

	return result;
}