我有以下代码:
wait.until {driver.find_element(:xpath, "//input[@class='btn btn-success Testserver']")}
element = driver.find_element(:xpath, "//input[@class='btn btn-success Testserver']")
element.click
wait.until {driver.find_element(:xpath, "//input[@class='btn btn-success Testserver2']")}
element = driver.find_element(:xpath, "//input[@class='btn btn-success Testserver2']")
element.click
我的问题是第3和第4行。当selenium单击第一个元素时,会导致页面重新加载。问题是第4行(wait.until)在执行重载之前找到元素。那会发生什么? Selenium认为该元素已经加载,它会尝试继续,之后页面重新加载并且selenium会抛出错误,导致它无法找到该元素。
Selenium::WebDriver::Error::StaleElementReferenceError: The element reference is stale. Either the element is no longer attached to the DOM or the page has been refreshed.
我该怎么办?当我在这些线路之间睡觉时,代码工作正常,但我不想使用睡眠导致不良做法。还有另一种方式吗?
感谢您的帮助!
答案 0 :(得分:1)
显然这是Selenium的一个众所周知的问题。如果旧页面和新页面都包含您正在测试的元素,则很难等待新页面加载。
有一些解决方法包括明确从ft.replace(...)
抢救并将其作为检查条件,以便您知道页面何时完成重新加载。请参阅How to get Selenium to wait for page load after a click。
在红宝石中,它看起来像这样(未经测试):
public class MainActivity extends AppCompatActivity {
private static String FRAGMENT_A_TAG = "FRAGMENT_A_TAG";
private static String FRAGMENT_B_TAG = "FRAGMENT_B_TAG";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
// Watch for button clicks.
Button button = (Button) findViewById(R.id.btn_switch_fragment);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
addFragmentToStack();
}
});
if (savedInstanceState == null) {
// Do first time initialization -- add initial fragment.
Fragment newFragment = FragmentA.newInstance();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.fragment_container, newFragment, FRAGMENT_A_TAG).commit();
}
}
private void addFragmentToStack() {
Fragment newFragment = FragmentB.newInstance();
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.fragment_container, newFragment, FRAGMENT_B_TAG);
ft.addToBackStack(null);
ft.commit();
}
}
public class FragmentA extends Fragment {
public FragmentA() {
// Required empty public constructor
}
public static FragmentA newInstance() {
FragmentA fragment = new FragmentA();
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
System.out.println("onCreate called");
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
System.out.println("onCreateView called");
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_a, container, false);
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
System.out.println("onPrepareOptionsMenu called");
super.onPrepareOptionsMenu(menu);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fragment_example_a, menu);
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
}
@Override
public void onDetach() {
super.onDetach();
}
@Override
public void onResume() {
super.onResume();
System.out.println("onResume called");
}
}
public class FragmentB extends Fragment {
public FragmentB() {
// Required empty public constructor
}
public static FragmentB newInstance() {
FragmentB fragment = new FragmentB();
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_b, container, false);
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fragment_example_b, menu);
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
}
@Override
public void onDetach() {
super.onDetach();
}
}