1. 程式人生 > >下拉框元素定位

下拉框元素定位

轉載自:http://www.cnblogs.com/tobecrazy/p/4752684.html

在機票預定的頁面,輸入出發城市和到達城市輸入框的時候, 發現直接使用sendkeys不好使,

大部分情況出現輸入某城市後沒有輸入進去, 經過幾天的研究,發現可以採取三種方式:

1. 先點選輸入框,待彈出 城市選擇框之後,點選相應的城市

2. 緩慢輸入城市的縮略字母或者城市的名字的部分,會顯示出待選城市的下拉列表,進而從下拉列表中選擇相應的城市.

3. 直接執行 js指令碼對input的value設定為想要的值

首先說一下第三種方式:

    JavascriptExecutor js = (JavascriptExecutor) driver;
        js.executeScript(
"arguments[0].value=\"北京\"", from_inpox);

 執行效果最好,

22:35:34.885 INFO - Executing: [execute script: arguments[0].value="北京", [[[Ch
romeDriver: chrome on XP (6452a4a961be7bffa2af9d1b63f3d111)] -> xpath: //div[@id
='js_flighttype_tab_domestic']//input[@name='fromCity']]]])

如上圖所演示,兩種方式均是使用者真實行為。

採取第一種方式:

  • 首先定位到輸入框
  • 點選輸入框
  • 從彈出的熱門城市框中點選所需要的城市
複製程式碼
WebElement from_inpox = driver
.findElement(By.xpath("//div[@id='js_flighttype_tab_domestic']//input[@name='fromCity']"));
Actions actions = new Actions(driver);
actions.moveToElement(from_inpox).click().perform();
driver.findElement(By
.xpath("//div[@data-panel='domesticfrom-flight-hotcity-from']//a[@class='js-hotcitylist' and text()='西安']"))
.click();
複製程式碼

這裡我並沒有直接使用click, 而是使用Actions,原因是我在對到達城市操作時,發現經常報element can't be clicked這樣的錯誤,

大意是,當要點選到達城市輸入框,其實是被上層的元素遮擋,沒法使用click方法,但是可以使用Actions的moveToElement方法之後可以click

或者採取滾動到該元素,呼叫JS

JavascriptExecutor jse = (JavascriptExecutor) driver;
jse.executeScript("arguments[0].scrollIntoView()",element);

之後就可進行click操作.

如果使用第二種方法,就會遇到一個很大的問題:

  如何定位到JS生成的下拉列表的城市?Firebug定位之前列表就消失!

看上去很難哈,反覆嘗試無所成, 最後突然想起既然是JS生成的,何不使用瀏覽器的JS debug功能,設定斷點一步一步

果不其然,藥到病除。nice job~

思路有了,跟我一起做,點開firebug ,切換到“指令碼”介面,首先在輸入框輸入單字母s,待彈出下拉列表後,單擊左側的插入斷點操作

你會發現該下拉框被凍結,不錯呦,之後切換到html介面進行定位。

不光是去哪網,像百度輸入框也可以採取這樣的辦法,JS設定斷點,js的彈出框,彈出選單就會凍結.

接下來我的輸入就是選擇下拉選單中所需城市:

複製程式碼
        from_inpox.clear();
        from_inpox.sendKeys("BJ");
        Thread.sleep(8000);
        By bj=new By.ByXPath("//div[@class='qcbox-fixed js-suggestcontainer']//td[contains(text(),'北京')]");
        if(isElementPresent(driver,bj,20))
        {
            driver.findElement(bj).click();
        }
複製程式碼

所要注意的是,下拉選單中未必彈出那麼快,需要做一次等待,在選擇下拉選單的時候需要做一次判斷,當然這個判斷方法是使用WebDriverWait

複製程式碼
/**
     * @author Young
     * @param driver
     * @param by
     * @param timeOut
     * @return
     */
    public static boolean isElementPresent(WebDriver driver, final By by, int timeOut) {
        WebDriverWait wait = new WebDriverWait(driver, timeOut);
        boolean isPresent = false;
        isPresent = wait.until(new ExpectedCondition<WebElement>() {
            @Override
            public WebElement apply(WebDriver d) {
                return d.findElement(by);
            }
        }).isDisplayed();
        return isPresent;

    }
複製程式碼

依然不夠完美,為什麼這麼說,如果元素沒有出現,並不是返回的false而是直接拋異常,並不是期望的,所以修改為findElements

如果找不到,返回List長度必然為0,進而返回false而不是丟擲異常

複製程式碼
/**
     * @author Young
     * @param driver
     * @param by
     * @param timeOut
     * @return
     * @throws InterruptedException
     */
    public static boolean isElementPresent(WebDriver driver, final By by,
            int timeOut) throws InterruptedException {
        boolean isPresent = false;
        Thread.sleep(timeOut * 1000);
        List<WebElement> we = driver.findElements(by);
        if (we.size() != 0) {
            isPresent = true;
        }
        return isPresent;
    }
複製程式碼

測試步驟:

1.選擇出發城市-> 北京

  到達城市->上海

  選擇今天之後的七天

  點選search button

2.選擇某帶“每段航班均需繳納稅費” 的訂單

複製程式碼
public static void main(String[] args) throws InterruptedException {
        WebDriver driver = DriverFactory.getChromeDriver();
        driver.get("http://flight.qunar.com/");
        driver.manage().window().maximize();
        driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
        driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);
        WebElement from_inpox = driver
                .findElement(By
                        .xpath("//div[@id='js_flighttype_tab_domestic']//input[@name='fromCity']"));
        WebElement to_inpox = driver
                .findElement(By
                        .xpath("//div[@id='js_flighttype_tab_domestic']//input[@name='toCity']"));
        WebElement from_date = driver
                .findElement(By
                        .xpath("//div[@id='js_flighttype_tab_domestic']//input[@name='fromDate']"));
        WebElement sigleWayCheckBox = driver
                .findElement(By
                        .xpath("//div[@id='js_flighttype_tab_domestic']//input[@class='inp_chk js-searchtype-oneway']"));
        if (!sigleWayCheckBox.isSelected()) {
            sigleWayCheckBox.click();
        }

        from_inpox.clear();
        from_inpox.sendKeys("BJ");
        Thread.sleep(8000);
        By bj = new By.ByXPath(
                "//div[@class='qcbox-fixed js-suggestcontainer']//td[contains(text(),'北京')]");
        if (isElementPresent(driver, bj, 20)) {
            driver.findElement(bj).click();
        }

        to_inpox.clear();
        to_inpox.sendKeys("SH");
        Thread.sleep(8000);
        By sh = new By.ByXPath(
                "//div[@class='qcbox-fixed js-suggestcontainer']//td[contains(text(),'上海')]");
        if (isElementPresent(driver, sh, 20)) {
            driver.findElement(sh).click();
        }

        // Actions actions = new Actions(driver);
        // actions.moveToElement(from_inpox).click().perform();
        // driver.findElement(
        // By.xpath("//div[@data-panel='domesticfrom-flight-hotcity-from']//a[@class='js-hotcitylist' and text()='西安']"))
        // .click();
        // driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
        // driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);
        // actions.moveToElement(to_inpox).click().perform();
        // driver.findElement(
        // By.xpath("//div[@data-panel='domesticto-flight-hotcity-to']//a[@class='js-hotcitylist' and text()='北京']"))
        // .click();
        // driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
        // driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);
        from_date.clear();
        from_date.sendKeys(getDateAfterToday(7));
        WebElement search = driver
                .findElement(By
                        .xpath("//div[@id='js_flighttype_tab_domestic']//button[@class='btn_search']"));
        search.submit();
        driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
        driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);
        WebElement page2 = driver.findElement(By
                .xpath("//div[@id='hdivPager']/a[@value='2']"));
        JavascriptExecutor jse = (JavascriptExecutor) driver;
        jse.executeScript("arguments[0].scrollIntoView()", page2);
        page2.click();

        driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
        driver.manage().timeouts().pageLoadTimeout(30, TimeUnit.SECONDS);
        driver.findElement(
                By.xpath("(//div[@class='avt_trans']//p[contains(text(),'每段航班均需繳納稅費')]/ancestor::div//div[@class='a_booking']/a)[3]"))
                .click();
        driver.findElement(
                By.xpath("//div[@id='flightbarXI883']//div[@class='t_bk']/a"))
                .click();
    }

    public static String getDateAfterToday(int dateAfterToday) {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, +dateAfterToday);
        System.out.println(cal.getTime().toString());
        Date date = cal.getTime();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        System.out.println(df.format(date));
        return df.format(date);
    }

    /**
     * @author Young
     * @param driver
     * @param by
     * @param timeOut
     * @return
     * @throws InterruptedException
     */
    public static boolean isElementPresent(WebDriver driver, final By by,
            int timeOut) throws InterruptedException {
        boolean isPresent = false;
        Thread.sleep(timeOut * 1000);
        List<WebElement> we = driver.findElements(by);
        if (we.size() != 0) {
            isPresent = true;
        }
        return isPresent;
    }
複製程式碼

效果如下: