Как проверить видимость элемента, который может присутствовать или не присутствовать?

Рассмотрите этот URL: https://sfbay.craigslist.org/pen/apa/5759740929.html Когда вы нажмете кнопку ответа, вы увидите всплывающее окно div с вариантами ответа. Див может иметь или не иметь номера телефонов и имя контактного лица.

Я сделал некоторый код для этого, и я ожидаю работать, как указано в пунктах ниже.

1- Если нажата кнопка ответа, дождитесь появления всплывающего окна параметров ответа. Когда всплывающее окно будет видно, ищите любые номера телефонов и извлекайте их.

2- Если во всплывающем окне нет номеров, ничего не делайте (это потому, что человек не хочет делиться своим номером телефона).

3- Если кто-то пытается извлечь телефонные номера / имена, когда всплывающее окно не открыто, то выдается исключение времени выполнения, в котором говорится, что кнопка ответа не нажата.

Почему код не работает, когда я использую wait_for_reply_options_popup_to_be_visible(), но проходит, когда я использую это: wait_for_calling_options_to_be_visible();

Пожалуйста, помогите мне понять, почему и решить эту проблему. Спасибо!

import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.util.List;

import static Utils.extract_phone_numbers;

public class Temp {
    private static final WebDriver browser = new ChromeDriver();
    private static String url = "https://sfbay.craigslist.org/pen/apa/5759740929.html";

    private WebElement reply_btn;
    private String reply_btn_xpath = "//button[contains(concat(\" \", normalize-space(@class), \" \"), \" "
            + "reply_button" + " \")]";
    private By reply_btn_loc = By.xpath(reply_btn_xpath);


    private String reply_options_xpath = "//button[contains(concat(\" \", normalize-space(@class), \" \"), \" "
            + "reply_options" + " \")]";
    private By reply_options_loc = By.xpath(reply_options_xpath);

    private String call_options_xpath = "//b[contains(text(), 'call') or contains(text(), 'text')]";
    private By call_options_loc = By.xpath(call_options_xpath);

    public String phone_xpath = "following-sibling::ul/li";
    public By phone_loc = By.xpath(phone_xpath);

    @Before
    public void before_each_test() {
        browser.get(url);
        load_elements();
    }

    @Test
    public void get_phone_number() throws Exception {
        reply_btn.click();
        List<String> phones = get_calling_or_texting_options();
        System.out.println(phones);
    }

    private void load_elements() {
        reply_btn = new WebDriverWait(browser, 5).until(
                ExpectedConditions.presenceOfElementLocated(reply_btn_loc));
    }

    private void wait_for_calling_options_to_be_visible(){
        new WebDriverWait(browser, 5).until(ExpectedConditions.visibilityOfElementLocated(call_options_loc));
    }

    private void wait_for_reply_options_popup_to_be_visible(){
        new WebDriverWait(browser, 5).until(ExpectedConditions.visibilityOfElementLocated(reply_options_loc));
    }

    private List<String> get_calling_or_texting_options() {
        wait_for_reply_options_popup_to_be_visible();
        //wait_for_calling_options_to_be_visible();

        //Look for any element which contains call or text. Their sibling elements should have a number.
        List<WebElement> calling_options = browser.findElements(call_options_loc);
        WebElement calling_option = calling_options.get(0);

        if (calling_options.size() > 0) {
            //Get the sibling elements which contain phone numbers.
            WebElement phone_info = calling_option.findElement(phone_loc);

            //Remove all the extra text and extract only the phone number.
            List<String> phones = extract_phone_numbers(phone_info.getText());

            return phones;
        } else {
            String error = "Cannot get list of contact numbers! Please click the reply button first!";
            throw new RuntimeException(error);
        }

    }

}

Трассировки стека:

org.openqa.selenium.TimeoutException: Timed out after 5 seconds waiting for visibility of element located by By.xpath: //button[contains(concat(" ", normalize-space(@class), " "), " reply_options ")].......
    at org.openqa.selenium.support.ui.WebDriverWait.timeoutException(WebDriverWait.java:80)
    at org.openqa.selenium.support.ui.FluentWait.until(FluentWait.java:261)
    at src.Temp.wait_for_reply_options_popup_to_be_visible(Temp.java:59)
    at src.Temp.get_calling_or_texting_options(Temp.java:63)
    at src.Temp.get_phone_number(Temp.java:45)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    .......
Caused by: org.openqa.selenium.NoSuchElementException: no such element
  (Session info: chrome=52.0.2743.116)
  (Driver info: chromedriver=2.9.248315,platform=Windows NT 6.1 SP1 x86_64) (WARNING: The server did not provide any stacktrace information)
Command duration or timeout: 9 milliseconds
For documentation on this error, please visit: http://seleniumhq.org/exceptions/no_such_element.html..........
............
*** Element info: {Using=xpath, value=//button[contains(concat(" ", normalize-space(@class), " "), " reply_options ")]}
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
    at org.openqa.selenium.remote.ErrorHandler.createThrowable(ErrorHandler.java:206)
    ...........

2 ответа

Решение

WebElement объекты скажут вам, если они видны / включены через встроенную функцию.

try{
    if(someElement.isDisplayed()) {
        // Do something...
    } else {
        // Do nothing...
    }
} catch (Exception e) {
    // Do nothing or handle exception...
}

Кстати, обычно лучше иметь больше... кратких имен для функций для удобства чтения. т.е. wait_for_reply_options_popup_to_be_visible() возможно waitForReplyOptions(),

РЕДАКТИРОВАТЬ: прямо из репо, предлагается сделать свой собственный метод, чтобы сделать эту проверку, как показано ниже:

public static boolean isPresentAndDisplayed(final WebElement element) {
    try {
        return element.isDisplayed();
    } catch (NoSuchElementException e) {
        return false;
    }
}

Вы должны создать метод с помощью try catch, как указано в записи выше. Но я предлагаю не использовать сам метод isDisplay(). Вместо этого вы должны сделать метод с использованием FluentWait()

public WebElement visibilityWait(int timeInMilliSeconds, By by) {
    WebElement element = null;
    try {
        element = new FluentWait<>(webDriver).
            withTimeout(timeoutInMilliSeconds, TimeUnit.MILLISECONDS).
            pollingEvery(500, TimeUnit.MILLISECONDS).
            ignoring(NotFoundException.class).ignoring(NoSuchElementException.class).
            until(visibilityOfElementLocated(by));
    } catch (TimeoutException ex) {
        logger.warn("Ignore TimeoutException: ", ex.getMessage());
    }
    return element;
}

Эти методы возвращают элемент, только если он присутствует и видим, если он не возвращает ноль. Вы можете указать тайм-аут для вашего дела, например, 15 секунд, я не знаю.

PS: Кстати, если один из ваших методов работает, а другой нет, проверьте еще раз ваши xpath. Больше ничего не могу сказать, не увидев сайт:)

Другие вопросы по тегам