由于页面重新加载,Selenium + Ruby问题

时间:2016-10-11 09:00:09

标签: ruby-on-rails ruby selenium selenium-webdriver

我有以下代码:

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.

我该怎么办?当我在这些线路之间睡觉时,代码工作正常,但我不想使用睡眠导致不良做法。还有另一种方式吗?

感谢您的帮助!

1 个答案:

答案 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();

    }

}