Commit 2315de34 authored by Ian Struiksma's avatar Ian Struiksma Committed by Commit Bot

Add click fallback action for autofill tests

Several sites were failing on windows autofill tests. The main issue
seems to be the resolution on windows bot that causes the sites to
sometimes render differently than when they were recorded.

One site needs different behavior for a button click on replay so
added a new action that will first check for a different element's
presence before trying to find the button to click.

Updated site recipes for 5 sites, so cipd version was updated:
sephora (removed a visibility constraint)
indigo (same)
newegg (added extra clicks to reset phone/zip fields to verify)
rue21 (rerecorded site on smaller resolution and used click fallback)
crate_and_barrel (forced payment page load)

Bug: 984664
Change-Id: Ic7d11082a2b4af53779281fcd27dce65753bac37
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1888742
Commit-Queue: Ian Struiksma <ianstruiksma@google.com>
Auto-Submit: Ian Struiksma <ianstruiksma@google.com>
Reviewed-by: default avatarDominic Battré <battre@chromium.org>
Cr-Commit-Position: refs/heads/master@{#710922}
parent 9c5365d7
...@@ -450,7 +450,7 @@ deps = { ...@@ -450,7 +450,7 @@ deps = {
'packages': [ 'packages': [
{ {
'package': 'chromium/chrome/test/data/autofill/captured_sites', 'package': 'chromium/chrome/test/data/autofill/captured_sites',
'version': '23EuJes_tRa4KkcqAuvDc48MlYCQwVKmjv64tpGllr8C', 'version': 'o7OTl3c2uPbxtCuWl68YXFBBErGlWC8mzH8NUwAR6QwC',
} }
], ],
'condition': 'checkout_chromium_autofill_test_dependencies', 'condition': 'checkout_chromium_autofill_test_dependencies',
......
...@@ -680,6 +680,10 @@ bool TestRecipeReplayer::ReplayRecordedActions( ...@@ -680,6 +680,10 @@ bool TestRecipeReplayer::ReplayRecordedActions(
} else if (base::CompareCaseInsensitiveASCII(*type, "click") == 0) { } else if (base::CompareCaseInsensitiveASCII(*type, "click") == 0) {
if (!ExecuteClickAction(*action)) if (!ExecuteClickAction(*action))
return false; return false;
} else if (base::CompareCaseInsensitiveASCII(*type, "clickIfNotSeen") ==
0) {
if (!ExecuteClickIfNotSeenAction(*action))
return false;
} else if (base::CompareCaseInsensitiveASCII(*type, "closeTab") == 0) { } else if (base::CompareCaseInsensitiveASCII(*type, "closeTab") == 0) {
if (!ExecuteCloseTabAction(*action)) if (!ExecuteCloseTabAction(*action))
return false; return false;
...@@ -840,6 +844,22 @@ bool TestRecipeReplayer::ExecuteClickAction( ...@@ -840,6 +844,22 @@ bool TestRecipeReplayer::ExecuteClickAction(
return true; return true;
} }
bool TestRecipeReplayer::ExecuteClickIfNotSeenAction(
const base::DictionaryValue& action) {
std::string xpath;
content::RenderFrameHost* frame;
if (ExtractFrameAndVerifyElement(action, &xpath, &frame, false, false,
true)) {
return true;
} else {
const std::string* click_xpath_text =
FindPopulateString(action, "clickSelector", "click xpath selector");
base::Value click_action = action.Clone();
click_action.SetStringKey("selector", *click_xpath_text);
return ExecuteClickAction(base::Value::AsDictionaryValue(click_action));
}
}
bool TestRecipeReplayer::ExecuteCloseTabAction( bool TestRecipeReplayer::ExecuteCloseTabAction(
const base::DictionaryValue& action) { const base::DictionaryValue& action) {
VLOG(1) << "Closing Active Tab"; VLOG(1) << "Closing Active Tab";
...@@ -1308,7 +1328,8 @@ bool TestRecipeReplayer::ExtractFrameAndVerifyElement( ...@@ -1308,7 +1328,8 @@ bool TestRecipeReplayer::ExtractFrameAndVerifyElement(
std::string* xpath, std::string* xpath,
content::RenderFrameHost** frame, content::RenderFrameHost** frame,
bool set_focus, bool set_focus,
bool relaxed_visibility) { bool relaxed_visibility,
bool ignore_failure) {
if (!GetTargetHTMLElementXpathFromAction(action, xpath)) if (!GetTargetHTMLElementXpathFromAction(action, xpath))
return false; return false;
...@@ -1326,7 +1347,8 @@ bool TestRecipeReplayer::ExtractFrameAndVerifyElement( ...@@ -1326,7 +1347,8 @@ bool TestRecipeReplayer::ExtractFrameAndVerifyElement(
if (relaxed_visibility) if (relaxed_visibility)
visibility_enum_val &= ~kReadyStateOnTop; visibility_enum_val &= ~kReadyStateOnTop;
if (!WaitForElementToBeReady(*xpath, visibility_enum_val, *frame)) if (!WaitForElementToBeReady(*xpath, visibility_enum_val, *frame,
ignore_failure))
return false; return false;
if (set_focus) { if (set_focus) {
...@@ -1412,22 +1434,29 @@ bool TestRecipeReplayer::GetIFrameOffsetFromIFramePath( ...@@ -1412,22 +1434,29 @@ bool TestRecipeReplayer::GetIFrameOffsetFromIFramePath(
bool TestRecipeReplayer::WaitForElementToBeReady( bool TestRecipeReplayer::WaitForElementToBeReady(
const std::string& xpath, const std::string& xpath,
const int visibility_enum_val, const int visibility_enum_val,
content::RenderFrameHost* frame) { content::RenderFrameHost* frame,
bool ignore_failure) {
std::vector<std::string> state_assertions; std::vector<std::string> state_assertions;
state_assertions.push_back(base::StringPrintf( state_assertions.push_back(base::StringPrintf(
"return automation_helper.isElementWithXpathReady(`%s`, %d);", "return automation_helper.isElementWithXpathReady(`%s`, %d);",
xpath.c_str(), visibility_enum_val)); xpath.c_str(), visibility_enum_val));
return WaitForStateChange(frame, state_assertions, default_action_timeout); return WaitForStateChange(
frame, state_assertions,
ignore_failure ? click_fallback_timeout : default_action_timeout,
ignore_failure);
} }
bool TestRecipeReplayer::WaitForStateChange( bool TestRecipeReplayer::WaitForStateChange(
content::RenderFrameHost* frame, content::RenderFrameHost* frame,
const std::vector<std::string>& state_assertions, const std::vector<std::string>& state_assertions,
const base::TimeDelta& timeout) { const base::TimeDelta& timeout,
bool ignore_failure) {
base::TimeTicks start_time = base::TimeTicks::Now(); base::TimeTicks start_time = base::TimeTicks::Now();
while (!AllAssertionsPassed(frame, state_assertions)) { while (!AllAssertionsPassed(frame, state_assertions)) {
if (base::TimeTicks::Now() - start_time > timeout) { if (base::TimeTicks::Now() - start_time > timeout) {
if (!ignore_failure) {
ADD_FAILURE() << "State change hasn't completed within timeout."; ADD_FAILURE() << "State change hasn't completed within timeout.";
}
return false; return false;
} }
WaitTillPageIsIdle(); WaitTillPageIsIdle();
......
...@@ -38,6 +38,9 @@ const base::TimeDelta default_action_timeout = base::TimeDelta::FromSeconds(30); ...@@ -38,6 +38,9 @@ const base::TimeDelta default_action_timeout = base::TimeDelta::FromSeconds(30);
// an action. The Captured Site Automation Framework uses this timeout to // an action. The Captured Site Automation Framework uses this timeout to
// break out of a wait loop after a hover action. // break out of a wait loop after a hover action.
const base::TimeDelta visual_update_timeout = base::TimeDelta::FromSeconds(20); const base::TimeDelta visual_update_timeout = base::TimeDelta::FromSeconds(20);
// The amount of time to do a precheck on the page before going to a click
// fallback action.
const base::TimeDelta click_fallback_timeout = base::TimeDelta::FromSeconds(5);
// When we cause a scroll event, make sure we give the page a moment to react // When we cause a scroll event, make sure we give the page a moment to react
// before continuing. // before continuing.
const base::TimeDelta scroll_wait_timeout = base::TimeDelta::FromSeconds(2); const base::TimeDelta scroll_wait_timeout = base::TimeDelta::FromSeconds(2);
...@@ -250,6 +253,7 @@ class TestRecipeReplayer { ...@@ -250,6 +253,7 @@ class TestRecipeReplayer {
const std::unique_ptr<base::DictionaryValue>& recipe); const std::unique_ptr<base::DictionaryValue>& recipe);
bool ExecuteAutofillAction(const base::DictionaryValue& action); bool ExecuteAutofillAction(const base::DictionaryValue& action);
bool ExecuteClickAction(const base::DictionaryValue& action); bool ExecuteClickAction(const base::DictionaryValue& action);
bool ExecuteClickIfNotSeenAction(const base::DictionaryValue& action);
bool ExecuteCoolOffAction(const base::DictionaryValue& action); bool ExecuteCoolOffAction(const base::DictionaryValue& action);
bool ExecuteCloseTabAction(const base::DictionaryValue& action); bool ExecuteCloseTabAction(const base::DictionaryValue& action);
bool ExecuteHoverAction(const base::DictionaryValue& action); bool ExecuteHoverAction(const base::DictionaryValue& action);
...@@ -281,14 +285,17 @@ class TestRecipeReplayer { ...@@ -281,14 +285,17 @@ class TestRecipeReplayer {
std::string* xpath, std::string* xpath,
content::RenderFrameHost** frame, content::RenderFrameHost** frame,
bool set_focus = false, bool set_focus = false,
bool relaxed_visibility = false); bool relaxed_visibility = false,
bool ignore_failure = false);
bool WaitForElementToBeReady(const std::string& xpath, bool WaitForElementToBeReady(const std::string& xpath,
const int visibility_enum_val, const int visibility_enum_val,
content::RenderFrameHost* frame); content::RenderFrameHost* frame,
bool ignore_failure = false);
bool WaitForStateChange( bool WaitForStateChange(
content::RenderFrameHost* frame, content::RenderFrameHost* frame,
const std::vector<std::string>& state_assertions, const std::vector<std::string>& state_assertions,
const base::TimeDelta& timeout = default_action_timeout); const base::TimeDelta& timeout = default_action_timeout,
bool ignore_failure = false);
bool AllAssertionsPassed(const content::ToRenderFrameHost& frame, bool AllAssertionsPassed(const content::ToRenderFrameHost& frame,
const std::vector<std::string>& assertions); const std::vector<std::string>& assertions);
bool ExecuteJavaScriptOnElementByXpath( bool ExecuteJavaScriptOnElementByXpath(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment