ทดสอบว่าองค์ประกอบมีอยู่โดยใช้ซีลีเนียม WebDriver หรือไม่


163

มีวิธีทดสอบว่ามีองค์ประกอบอยู่หรือไม่? เมธอด findElement ใด ๆ จะสิ้นสุดลงในข้อยกเว้น แต่นั่นไม่ใช่สิ่งที่ฉันต้องการเพราะอาจเป็นเพราะองค์ประกอบนั้นไม่มีอยู่และไม่เป็นไรนั่นไม่ใช่การทดสอบที่ล้มเหลวดังนั้นข้อยกเว้นจึงไม่สามารถแก้ไขได้

ฉันพบโพสต์นี้: Selenium c # Webdriver: รอจนกว่าจะมีองค์ประกอบ แต่นี่สำหรับ C # และฉันไม่ค่อยเก่ง ทุกคนสามารถแปลรหัสเป็น Java ได้หรือไม่ ฉันขอโทษพวกฉันลองใช้ Eclipse แต่ฉันไม่เข้าใจในโค้ด Java

นี่คือรหัส:

public static class WebDriverExtensions{
    public static IWebElement FindElement(this IWebDriver driver, By by, int timeoutInSeconds){

        if (timeoutInSeconds > 0){
            var wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeoutInSeconds));
            return wait.Until(drv => drv.FindElement(by));
        }

        return driver.FindElement(by);
    }
}

ฉันมีสองวิธีที่ทำงานอย่างมีประสิทธิภาพในการตรวจสอบวัตถุ แต่ขึ้นอยู่กับสิ่งที่คุณต้องการจะทำกับมัน ตัวอย่างเช่นคุณต้องการค้นหาองค์ประกอบจนกว่าจะมีอยู่คุณต้องการค้นหามันจนกว่าจะไม่มีอยู่อีกต่อไปหรือคุณต้องการลองค้นหามันหรือไม่?
CBRRacer

1
Java คล้ายกับ C # ฉันคิดว่าหนึ่งในปัญหาหลักที่คุณพบคือใน java คือ WebElement แทนที่จะเป็น IWebElement
CBRRacer

คุณรู้เกี่ยวกับวิธีการรอนัย? โดยการตั้งค่านี้ขึ้นในช่วงเริ่มต้นของการทดสอบที่คุณไม่เคยมีการตรวจสอบสำหรับการดำรงอยู่ขององค์ประกอบตามที่มีการใช้ค่าการรอคอยโดยปริยายโพลล์ แต่ถ้ามันเกินกว่าค่าที่จะโยนยกเว้น
บ๊อบอีแวนส์

นี่คือโพสต์ของฉันเกี่ยวกับ WebDriverWait ใน Java: WebDriverWait

หากกรณีใดกรณีหนึ่งก็โอเคอาจเป็นปัญหาสำหรับประสิทธิภาพการทดสอบเนื่องจากเวลารอคอยที่เกี่ยวข้องกับการรอองค์ประกอบที่คุณไม่คาดว่าจะมีอยู่จริงจะเพิ่มขึ้น ฉันใช้แฮ็คสองสามครั้งเพื่อรอเวลา แต่ยังไม่พบวิธีแก้ปัญหาที่ดีสำหรับเรื่องนี้
mrfreester

คำตอบ:


277

ใช้แทนfindElementsfindElement

findElements จะส่งคืนรายการว่างถ้าไม่พบองค์ประกอบที่ตรงกันแทนที่จะเป็นข้อยกเว้น

ในการตรวจสอบว่ามีองค์ประกอบอยู่คุณสามารถลองทำสิ่งนี้ได้

Boolean isPresent = driver.findElements(By.yourLocator).size() > 0

สิ่งนี้จะคืนค่าเป็นจริงหากพบองค์ประกอบอย่างน้อยหนึ่งรายการและเป็นเท็จหากไม่มีอยู่

เอกสารแนะนำอย่างเป็นทางการแนะนำวิธีนี้:

ไม่ควรใช้ findElement เพื่อค้นหาอิลิเมนต์ที่ไม่มีอยู่ให้ใช้ findElements (By) และยืนยันการตอบสนองความยาวเป็นศูนย์แทน


32
วิธีนี้จะเพิ่มเวลาในการทดสอบของคุณ คุณไม่สามารถใช้เทคนิคนี้ได้ทุกที่
Droogans

8
@Dogogans - ฉันจะไม่เพิ่มเวลาในการทดสอบของคุณ เหตุผลที่จะไม่เป็นเพราะการรอปริยายเริ่มต้นยังคงเป็น 0 หากคุณเพิ่มการรอปริยายโดยปริยายฉันก็ยอมรับว่ามันจะเป็นเช่นนั้น แต่มันก็ไม่ได้เป็นอย่างนั้น
djangofan

1
โทรดีจังฟาน! ฉันประสบความสำเร็จในการใช้กลยุทธ์นี้โดยการเปลี่ยนการหมดเวลาโดยนัยของการรอเป็นศูนย์จากนั้นเปลี่ยนกลับเป็นค่าก่อนหน้า
มรกต

3
สิ่งนี้ให้ข้อยกเว้น NoSuchElementFound ซึ่งเป็นความอัปยศอย่างที่ฉันหวังว่าจะใช้เพื่อหลีกเลี่ยงการยกเว้นข้อยกเว้นนั้นในอินสแตนซ์ที่กำหนด

1
วิธีที่ง่ายกว่ามากคือการใช้: if (driver.getPageSource (). มี ("ข้อความในหน้า")) {} หากหน้านั้นมีข้อความนี้เงื่อนไขจะเป็นจริงมิฉะนั้นจะเป็นเท็จและคุณสามารถโค้ดได้ ตาม
pradyot

56

เกี่ยวกับวิธีการส่วนตัวที่จะมองหาองค์ประกอบและพิจารณาว่ามันเป็นเช่นนี้หรือไม่:

private boolean existsElement(String id) {
    try {
        driver.findElement(By.id(id));
    } catch (NoSuchElementException e) {
        return false;
    }
    return true;
}

นี่จะค่อนข้างง่ายและทำงานได้

แก้ไข: คุณสามารถไปต่อและรับBy elementLocatorพารามิเตอร์เป็นกำจัดปัญหาถ้าคุณต้องการค้นหาองค์ประกอบด้วยสิ่งอื่นที่ไม่ใช่ id


3
ใช่นี่คือวิธีที่จะไป ไม่เข้าใจว่าทำไมผู้คนถึงเพิกเฉยด้วยวิธีนี้และนับองค์ประกอบที่เข้าคู่กันโดยดูว่าผลลัพธ์นั้นเป็น 0 หรือไม่
Ralph Lavelle

45
ฉันต้องบอกว่าใช้การยกเว้นเพื่อควบคุมการไหลของโปรแกรมไม่ใช่วิธีที่ดีที่สุด
เดนนิส

2
ฮะ? มันเป็นข้อเสนอแนะของคุณ! มันเป็นวิธีที่ดีที่จะไปถ้าการทดสอบของคุณคาดว่าจะไม่พบองค์ประกอบ ในขณะที่คุณแสดงให้ส่งคืนค่า null และ assert.isnull หรือ isnotnull ซึ่งเป็นวิธีที่มีความหมายในการทดสอบว่ามีสิ่งใดบ้าง
Ralph Lavelle

2
ในกรณีที่ฉันตีความคำถามผิด "มีวิธีทดสอบว่ามีองค์ประกอบหรือไม่" ฉันยินดีที่จะเรียนรู้ว่าทำไมความคิดเห็นของคุณแตกต่างกันหรือไม่ว่านี่เป็นคำตอบที่ถูกกฎหมายหรือไม่
Dennis

อาจต้องการลดเวลารอ ตอนนี้ถ้าองค์ประกอบไม่มีอยู่คุณต้องรอ "30 วินาที" ก่อนที่ฟังก์ชันจะส่งคืนค่าเท็จ
Jason Smiley

14

ฉันพบว่ามันใช้งานได้กับ Java:

WebDriverWait waiter = new WebDriverWait(driver, 5000);
waiter.until( ExpectedConditions.presenceOfElementLocated(by) );
driver.FindElement(by);

18
presenceOfElementLocatedจะโยนข้อยกเว้นหากไม่พบองค์ประกอบในความพยายามใด ๆ เพื่อหลีกเลี่ยงปัญหานี้เพิ่มwait.ignoring(NoSuchElementException.class);คำสั่งระหว่างบรรทัดแรกและบรรทัดที่สอง
Steve Chambers

8
public static WebElement FindElement(WebDriver driver, By by, int timeoutInSeconds)
{
    WebDriverWait wait = new WebDriverWait(driver, timeoutInSeconds);
    wait.until( ExpectedConditions.presenceOfElementLocated(by) ); //throws a timeout exception if element not present after waiting <timeoutInSeconds> seconds
    return driver.findElement(by);
}

5

ฉันมีปัญหาเดียวกัน สำหรับฉันขึ้นอยู่กับระดับการอนุญาตของผู้ใช้ลิงก์บางปุ่มและองค์ประกอบอื่น ๆ จะไม่ปรากฏบนหน้าเว็บ ส่วนหนึ่งของชุดทดสอบของฉันกำลังทดสอบว่าองค์ประกอบที่ควรหายไปหายไป ฉันใช้เวลาหลายชั่วโมงในการคิดออก ในที่สุดฉันก็พบทางออกที่สมบูรณ์แบบ

สิ่งนี้จะบอกเบราว์เซอร์ให้ค้นหาองค์ประกอบใด ๆ และทั้งหมดตามที่ระบุ ถ้ามันส่งผลให้0ให้แสดงว่าไม่พบองค์ประกอบตามข้อมูลจำเพาะ แล้วฉันมีรหัสรันคำสั่ง if เพื่อแจ้งให้เราทราบว่าไม่พบ

นี้อยู่ในดังนั้นคำแปลที่จะต้องมีการดำเนินการเพื่อC# Javaแต่ไม่ควรยากเกินไป

public void verifyPermission(string link)
{
    IList<IWebElement> adminPermissions = driver.FindElements(By.CssSelector(link));
    if (adminPermissions.Count == 0)
    {
        Console.WriteLine("User's permission properly hidden");
    }
}

นอกจากนี้ยังมีเส้นทางอื่นที่คุณสามารถทำได้โดยขึ้นอยู่กับสิ่งที่คุณต้องการสำหรับการทดสอบของคุณ

ตัวอย่างต่อไปนี้กำลังตรวจสอบเพื่อดูว่ามีองค์ประกอบที่เฉพาะเจาะจงมากในหน้าเว็บหรือไม่ ขึ้นอยู่กับการมีอยู่ขององค์ประกอบฉันมีการทดสอบดำเนินการถ้าอื่น

หากองค์ประกอบนั้นมีอยู่และปรากฏบนหน้าเว็บฉันconsole.writeแจ้งให้ฉันทราบและดำเนินการต่อ หากองค์ประกอบดังกล่าวมีอยู่ฉันไม่สามารถทำการทดสอบที่ฉันต้องการซึ่งเป็นเหตุผลหลักที่อยู่เบื้องหลังที่จำเป็นต้องตั้งค่านี้

หากองค์ประกอบไม่มีอยู่และจะไม่ปรากฏบนหน้า ฉันมีอย่างอื่นในถ้าอื่นดำเนินการทดสอบ

IList<IWebElement> deviceNotFound = driver.FindElements(By.CssSelector("CSS LINK GOES HERE"));
//if the element specified above results in more than 0 elements and is displayed on page execute the following, otherwise execute whats in the else statement
if (deviceNotFound.Count > 0 && deviceNotFound[0].Displayed){
    //script to execute if element is found
} else {
    //Test script goes here.
}

ฉันรู้ว่าฉันสายเล็กน้อยในการตอบสนองต่อ OP หวังว่านี่จะช่วยให้ใครบางคน!


5

ลองวิธีนี้: เรียกเมธอดนี้และส่งผ่านอาร์กิวเมนต์ 3 ตัว:

  1. ตัวแปร WebDriver // สมมติว่า driver_variable เป็นไดรเวอร์
  2. องค์ประกอบที่คุณจะตรวจสอบ ควรจัดทำจาก By method // ex: By.id ("id")
  3. จำกัด เวลาเป็นวินาที

ตัวอย่าง: waitForElementPresent (ไดรเวอร์, By.id ("id"), 10);

public static WebElement waitForElementPresent(WebDriver driver, final By by, int timeOutInSeconds) {

        WebElement element; 

        try{
            driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS); //nullify implicitlyWait() 

            WebDriverWait wait = new WebDriverWait(driver, timeOutInSeconds); 
            element = wait.until(ExpectedConditions.presenceOfElementLocated(by));

            driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); //reset implicitlyWait
            return element; //return the element
        } catch (Exception e) {
            e.printStackTrace();
        } 
        return null; 
    }

3

คุณสามารถทำให้โค้ดทำงานได้เร็วขึ้นโดยการลดการหมดเวลาของซีลีเนียมก่อนที่จะลองคำสั่ง catch

ฉันใช้รหัสต่อไปนี้เพื่อตรวจสอบว่ามีองค์ประกอบอยู่หรือไม่

protected boolean isElementPresent(By selector) {
    selenium.manage().timeouts().implicitlyWait(1, TimeUnit.SECONDS);
    logger.debug("Is element present"+selector);
    boolean returnVal = true;
    try{
        selenium.findElement(selector);
    } catch (NoSuchElementException e){
        returnVal = false;
    } finally {
        selenium.manage().timeouts().implicitlyWait(15, TimeUnit.SECONDS);
    }
    return returnVal;
}

นี่คือสิ่งที่ฉันใช้ในรหัสของฉัน ฉันปล่อยให้หมดเวลาซีลีเนียมเป็นค่าเริ่มต้นแล้วใช้สิ่งนี้
Nicholas DiP Piazza

2
ตั้งแต่เขียนคำตอบนี้ฉันได้เรียนรู้ว่าการใช้ ExpectedConditions ถือว่าเป็นรูปแบบที่ดีกว่า แต่การใช้คำสั่ง try catch ยังคงมีประโยชน์เมื่อพยายามที่จะพิจารณาว่าองค์ประกอบนั้นไม่มีอยู่หรือไม่
EsotericNonsense

ฉันติดอยู่กับซีลีเนียมรุ่นเก่าเพราะฉันต้องทดสอบ IE8 แต่ฉันจะลองดูเมื่อฉันสามารถอัพเกรดได้
Nicholas DiP Piazza

แต่ละครั้งที่วิธีการของคุณจะตั้งค่าการหมดเวลารอโดยนัย แต่อย่างมีเหตุผลเราควรตั้งค่าการรอโดยนัยเพียงครั้งเดียวหลังจากการเริ่มต้นวัตถุไดรเวอร์และการหมดเวลาถูกตั้งค่าเป็นเซสชันไดรเวอร์
Shekhar Swami

3

เขียนฟังก์ชัน / methos ต่อไปนี้โดยใช้ Java:

protected boolean isElementPresent(By by){
        try{
            driver.findElement(by);
            return true;
        }
        catch(NoSuchElementException e){
            return false;
        }
    }

เรียกใช้เมธอดพร้อมพารามิเตอร์ที่เหมาะสมระหว่างการยืนยัน


2

หากคุณใช้ rspec-Webdriver ใน ruby ​​คุณสามารถใช้สคริปต์นี้โดยสมมติว่าองค์ประกอบไม่ควรมีอยู่จริงและเป็นการทดสอบที่ผ่านไปแล้ว

ก่อนอื่นให้เขียนวิธีนี้ก่อนจากไฟล์ RB คลาสของคุณ

class Test
 def element_present?
    begin
        browser.find_element(:name, "this_element_id".displayed?
        rescue Selenium::WebDriver::Error::NoSuchElementError
            puts "this element should not be present"
        end
 end

จากนั้นในไฟล์ข้อมูลจำเพาะของคุณให้เรียกวิธีการนั้น

  before(:all) do    
    @Test= Test.new(@browser)
  end

 @Test.element_present?.should == nil

หากองค์ประกอบของคุณไม่ได้อยู่สเป็คของคุณจะผ่าน แต่ถ้าองค์ประกอบนั้นมีอยู่มันจะโยนข้อผิดพลาดการทดสอบล้มเหลว


2

สิ่งนี้ใช้ได้กับฉัน:

 if(!driver.findElements(By.xpath("//*[@id='submit']")).isEmpty()){
    //THEN CLICK ON THE SUBMIT BUTTON
}else{
    //DO SOMETHING ELSE AS SUBMIT BUTTON IS NOT THERE
}

มีปัญหาเดียวกันที่นี่: จะทำอย่างไรหากองค์ประกอบ "// * [@ id = 'submit']" ไม่มีอยู่? จากนั้นจะมีการโยนข้อยกเว้นดังนั้นหากเงื่อนไขไม่เคยประเมิน
MrBCut


1

โดยส่วนตัวแล้วฉันมักจะหาคำตอบข้างบนผสมกันและสร้างวิธีการยูทิลิตี้สแตติกที่สามารถใช้งานได้อีกครั้งซึ่งใช้size() > 0คำแนะนำ:

public Class Utility {
   ...
   public static boolean isElementExist(WebDriver driver, By by) {
      return driver.findElements(by).size() > 0;
   ...
}

นี่คือเรียบร้อยใช้งานได้อีกครั้งบำรุงรักษา ... ทุกสิ่งที่ดี ;-)


0

ในการค้นหาองค์ประกอบเฉพาะนั้นมีอยู่หรือไม่เราต้องใช้วิธี findElements () แทน findElement () ..

int i=driver.findElements(By.xpath(".......")).size();
if(i=0)
System.out.println("Element is not present");
else
System.out.println("Element is present");

มันใช้งานได้สำหรับฉัน .. แนะนำฉันถ้าฉันผิด ..


0

สิ่งนี้ควรทำ:

try {
    driver.findElement(By.id(id));
} catch (NoSuchElementException e) {
    //do what you need here if you were expecting
    //the element wouldn't exist
}

0

ให้โค้ดของฉัน ดังนั้นวิธีการด้านล่างจะตรวจสอบว่ามีองค์ประกอบ'ปุ่มสร้างแอปพลิเคชันใหม่ ' อยู่บนหน้าเว็บหรือไม่ โปรดทราบว่าฉันใช้เวลารอเป็น0วินาที

public boolean isCreateNewApplicationButtonVisible(){
    WebDriverWait zeroWait = new WebDriverWait(driver, 0);
    ExpectedCondition<WebElement> c = ExpectedConditions.presenceOfElementLocated(By.xpath("//input[@value='Create New Application']"));
    try {
        zeroWait.until(c);
        logger.debug("Create New Application button is visible");
        return true;
    } catch (TimeoutException e) {
        logger.debug("Create New Application button is not visible");
        return false;
    }
}

0

ฉันจะใช้สิ่งที่ชอบ (กับ Scala [รหัสในเก่า "ดี" Java 8 อาจคล้ายกับนี้]):

object SeleniumFacade {

  def getElement(bySelector: By, maybeParent: Option[WebElement] = None, withIndex: Int = 0)(implicit driver: RemoteWebDriver): Option[WebElement] = {
    val elements = maybeParent match {
      case Some(parent) => parent.findElements(bySelector).asScala
      case None => driver.findElements(bySelector).asScala
    }
    if (elements.nonEmpty) {
      Try { Some(elements(withIndex)) } getOrElse None
    } else None
  }
  ...
}

ดังนั้น

val maybeHeaderLink = SeleniumFacade getElement(By.xpath(".//a"), Some(someParentElement))

0

วิธีที่ง่ายที่สุดที่ฉันพบใน Java คือ:

List<WebElement> linkSearch=  driver.findElements(By.id("linkTag"));
int checkLink=linkSearch.size();
if(checkLink!=0){  //do something you want}

0

คุณสามารถลองรอโดยนัย:

WebDriver driver = new FirefoxDriver();
driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(10));
driver.Url = "http://somedomain/url_that_delays_loading";
IWebElement myDynamicElement = driver.FindElement(By.Id("someDynamicElement"));

หรือคุณสามารถลองหนึ่งอย่างชัดเจน:

IWebDriver driver = new FirefoxDriver();
driver.Url = "http://somedomain/url_that_delays_loading";
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
IWebElement myDynamicElement = wait.Until<IWebElement>((d) =>
    {
        return d.FindElement(By.Id("someDynamicElement"));
    });

อย่างชัดเจนจะตรวจสอบว่าองค์ประกอบมีอยู่ก่อนที่จะดำเนินการบางอย่าง การรอโดยปริยายสามารถโทรได้ทุกที่ในรหัส ตัวอย่างเช่นหลังจากการกระทำ AJAX บางอย่าง

มากกว่าที่คุณสามารถหาได้ที่ หน้า SeleniumHQ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.