“ องค์ประกอบไม่ได้เชื่อมต่อกับ DOM” StaleElementReferenceException แบบสุ่มอีกต่อไป


143

ฉันหวังว่ามันเป็นแค่ฉัน แต่ Selenium Webdriver ดูเหมือนเป็นฝันร้ายที่สมบูรณ์ เว็บเบราว์เซอร์ Chrome ใช้งานไม่ได้ในขณะนี้และไดรเวอร์อื่น ๆ ค่อนข้างไม่น่าเชื่อถือหรือดูเหมือนเป็นอย่างนั้น ฉันกำลังต่อสู้กับปัญหาหลายอย่าง แต่นี่คือปัญหาเดียว

การทดสอบของฉันจะล้มเหลวด้วยการสุ่ม

"org.openqa.selenium.StaleElementReferenceException: Element is no longer attached 
to the DOM    
System info: os.name: 'Windows 7', os.arch: 'amd64',
 os.version: '6.1', java.version: '1.6.0_23'"

ฉันใช้ webdriver เวอร์ชั่น 2.0b3 ฉันได้เห็นสิ่งนี้เกิดขึ้นกับไดรเวอร์ FF และ IE วิธีเดียวที่ฉันสามารถป้องกันได้คือเพิ่มการโทรจริงThread.sleepก่อนที่จะเกิดข้อยกเว้น นั่นเป็นวิธีแก้ปัญหาที่ไม่ดีดังนั้นฉันหวังว่าจะมีใครบางคนชี้ให้เห็นข้อผิดพลาดในส่วนของฉันที่จะทำให้ดีขึ้นทั้งหมด


26
หวังว่ามุมมอง 17k จะบ่งบอกว่าไม่ใช่แค่คุณเท่านั้น) นี่เป็นข้อยกเว้นที่น่าผิดหวังที่สุดของซีลีเนียม
Mark Mayo

4
48k ตอนนี้! ฉันมีปัญหาเดียวกัน ...
Gal

3
ฉันพบว่าซีลีเนียมเป็นขยะที่บริสุทธิ์และสมบูรณ์ ....
จอห์นสัน

4
60k ยังคงเป็นปัญหา :)
ปีเตอร์เดอบี้

ในกรณีของฉันมันเป็นเพราะการทำfrom selenium.common.exceptions import NoSuchElementException
เป่า Senkfuss

คำตอบ:


119

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

WebElement element = driver.findElement(By.id("foo"));
// DOM changes - page is refreshed, or element is removed and re-added
element.click();

ตอนนี้ถึงจุดที่คุณคลิกองค์ประกอบการอ้างอิงองค์ประกอบจะไม่ถูกต้องอีกต่อไป มันใกล้จะเป็นไปไม่ได้สำหรับ WebDriver ที่จะคาดเดาอย่างดีเกี่ยวกับทุกกรณีที่อาจเกิดขึ้น - ดังนั้นมันจึงส่งมือของคุณและให้การควบคุมแก่คุณซึ่งในฐานะผู้เขียนทดสอบ / แอพควรรู้ว่าอะไรจะเกิดขึ้นหรือไม่เกิดขึ้น สิ่งที่คุณต้องการทำคือรอจนกระทั่ง DOM อยู่ในสถานะที่คุณรู้ว่าสิ่งต่าง ๆ จะไม่เปลี่ยนแปลง ตัวอย่างเช่นการใช้ WebDriverWait เพื่อรอองค์ประกอบเฉพาะที่มีอยู่:

// times out after 5 seconds
WebDriverWait wait = new WebDriverWait(driver, 5);

// while the following loop runs, the DOM changes - 
// page is refreshed, or element is removed and re-added
wait.until(presenceOfElementLocated(By.id("container-element")));        

// now we're good - let's click the element
driver.findElement(By.id("foo")).click();

กระบวนการการปรากฏตัววิธี () จะมีลักษณะเช่นนี้:

private static Function<WebDriver,WebElement> presenceOfElementLocated(final By locator) {
    return new Function<WebDriver, WebElement>() {
        @Override
        public WebElement apply(WebDriver driver) {
            return driver.findElement(locator);
        }
    };
}

คุณค่อนข้างถูกต้องเกี่ยวกับไดรเวอร์ Chrome ปัจจุบันที่ค่อนข้างเสถียรและคุณยินดีที่ได้ยินว่าซีลีเนียม trunk มีไดรเวอร์ Chrome ที่เขียนใหม่ซึ่งการพัฒนาส่วนใหญ่ดำเนินการโดยนักพัฒนา Chromium ซึ่งเป็นส่วนหนึ่งของโครงสร้าง

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

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS)

จากประสบการณ์ของผมการรออย่างชัดเจนน่าเชื่อถือกว่าเสมอ


2
ฉันกำลังพูดอยู่หรือไม่ว่าไม่สามารถอ่านองค์ประกอบต่างๆลงในตัวแปรและนำกลับมาใช้ใหม่ได้อีกต่อไป? เพราะฉันมี WATiR DSL ที่แห้งและไดนามิกขนาดใหญ่ที่ต้องอาศัยองค์ประกอบการส่งผ่านและฉันพยายามพอร์ตไปยัง webdriver แต่ฉันมีปัญหาเดียวกัน โดยพื้นฐานแล้วฉันจะต้องเพิ่มรหัสเพื่ออ่านองค์ประกอบทั้งหมดในโมดูลอีกครั้งสำหรับทุกขั้นตอนการทดสอบที่เปลี่ยนแปลง DOM ...
kinofrost

สวัสดี ฉันขอถามได้ไหมว่า Function ประเภทใดในตัวอย่างนี้ ฉันหามันไม่เจอ .... ขอบคุณ!
ฮันนิบาล

1
@Hannibal: com.google.common.base.Function<F, T>ให้โดยฝรั่ง
Stephan202

@jarib ฉันประสบปัญหาเดียวกันนี้หนึ่งปีนับตั้งแต่การแก้ปัญหาของคุณ ปัญหาคือฉันกำลังเขียนสคริปต์ของฉันใน ruby ​​และไม่มีฟังก์ชั่นโดยใช้ชื่อของ 'การแสดงตน' ที่เป็นเท็จหรือสิ่งที่คล้ายกัน คำแนะนำใด ๆ
Amey

56
@jarib ฉันไม่เห็นด้วยกับสิ่งนี้เกิดจากการทดสอบที่ออกแบบมาไม่ดี เพราะแม้หลังจากองค์ประกอบปรากฏขึ้นหลังจากการโทร AJAX อาจมีรหัส jQuery ยังทำงานอยู่ซึ่งอาจทำให้เกิด StaleElementReferenceException และไม่มีอะไรที่คุณสามารถทำได้ยกเว้นการเพิ่มการรอที่ชัดเจนซึ่งดูไม่ดีนัก ฉันค่อนข้างคิดว่านี่เป็นข้อบกพร่องในการออกแบบใน WebDriver
ขบฉัน

10

ฉันสามารถใช้วิธีการเช่นนี้ได้สำเร็จ:

WebElement getStaleElemById(String id) {
    try {
        return driver.findElement(By.id(id));
    } catch (StaleElementReferenceException e) {
        System.out.println("Attempting to recover from StaleElementReferenceException ...");
        return getStaleElemById(id);
    }
}

ใช่มันเป็นเพียงการสำรวจความคิดเห็นองค์ประกอบจนกว่ามันจะไม่ถือว่าค้าง (สด?) ไม่เข้าใจถึงปัญหา แต่ฉันพบว่า WebDriver สามารถเลือกที่จะขว้างข้อยกเว้นนี้ได้ - บางครั้งฉันก็เข้าใจแล้วและบางครั้งก็ทำไม่ได้ หรืออาจเป็นได้ว่า DOM กำลังเปลี่ยนแปลงไป

ดังนั้นฉันจึงไม่ค่อยเห็นด้วยกับคำตอบข้างต้นว่าสิ่งนี้บ่งชี้ว่าการทดสอบที่เขียนไม่ดี ฉันได้รับมันในหน้าใหม่ที่ฉันไม่ได้มีปฏิสัมพันธ์ใด ๆ ฉันคิดว่ามีความไม่แน่นอนบางอย่างในวิธีแสดง DOM หรือในสิ่งที่ WebDriver ถือว่าค้าง


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

2
ฉันคิดว่าจะเป็นการดีกว่าถ้าเพิ่มตัวนับหรือบางอย่างดังนั้นเมื่อเราได้รับข้อผิดพลาดซ้ำ ๆ เราจะสามารถโยนข้อผิดพลาดนั้นได้ มิฉะนั้นหากมีข้อผิดพลาดเกิดขึ้นจริงคุณจะต้องวนซ้ำ
Sudara

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

10

ฉันได้รับข้อผิดพลาดนี้บางครั้งเมื่ออัปเดต AJAX อยู่ตรงกลาง Capybara ดูฉลาดพอที่จะรอการเปลี่ยนแปลง DOM (ดูทำไม Wait_until ถูกนำออกจาก Capybara ) แต่เวลารอเริ่มต้นที่ 2 วินาทีนั้นไม่เพียงพอในกรณีของฉัน เปลี่ยนเป็น _spec_helper.rb_ ด้วยเช่น

Capybara.default_max_wait_time = 5

2
สิ่งนี้แก้ไขปัญหาของฉันด้วย: ฉันได้รับ StaleElementReferenceError และเพิ่ม Capybara.default_max_wait_time เพื่อแก้ไขปัญหา
เบรนแดน

1

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

private void setElementLocator()
{
    this.locatorVariable = "selenium_" + DateTimeMethods.GetTime().ToString();
    ((IJavaScriptExecutor)this.driver).ExecuteScript(locatorVariable + " = arguments[0];", this.element);
}

private void RetrieveElement()
{
    this.element = (IWebElement)((IJavaScriptExecutor)this.driver).ExecuteScript("return " + locatorVariable);
}

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

นอกจากนี้ยังหลีกเลี่ยงการค้นหาองค์ประกอบอีกครั้ง

จอห์น


1

ฉันมีปัญหาเดียวกันและของฉันเกิดจากซีลีเนียมรุ่นเก่า ฉันไม่สามารถอัปเดตเป็นเวอร์ชันที่ใหม่กว่าได้เนื่องจากสภาพแวดล้อมการพัฒนา ปัญหาเกิดจาก HTMLUnitWebElement.switchFocusToThisIfNeeded () เมื่อคุณนำทางไปยังหน้าใหม่อาจเป็นไปได้ว่าองค์ประกอบที่คุณคลิกบนหน้าเก่าคือoldActiveElement(ดูด้านล่าง) ซีลีเนียมพยายามรับบริบทจากองค์ประกอบเก่าและล้มเหลว นั่นเป็นเหตุผลที่พวกเขาสร้างลองในการเปิดตัวในอนาคต

รหัสจากซีลีเนียม -htmlunit-driver เวอร์ชั่น <2.23.0:

private void switchFocusToThisIfNeeded() {
    HtmlUnitWebElement oldActiveElement =
        ((HtmlUnitWebElement)parent.switchTo().activeElement());

    boolean jsEnabled = parent.isJavascriptEnabled();
    boolean oldActiveEqualsCurrent = oldActiveElement.equals(this);
    boolean isBody = oldActiveElement.getTagName().toLowerCase().equals("body");
    if (jsEnabled &&
        !oldActiveEqualsCurrent &&
        !isBody) {
      oldActiveElement.element.blur();
      element.focus();
    }
}

รหัสจากซีลีเนียม -htmlunit-driver เวอร์ชั่น> = 2.23.0:

private void switchFocusToThisIfNeeded() {
    HtmlUnitWebElement oldActiveElement =
        ((HtmlUnitWebElement)parent.switchTo().activeElement());

    boolean jsEnabled = parent.isJavascriptEnabled();
    boolean oldActiveEqualsCurrent = oldActiveElement.equals(this);
    try {
        boolean isBody = oldActiveElement.getTagName().toLowerCase().equals("body");
        if (jsEnabled &&
            !oldActiveEqualsCurrent &&
            !isBody) {
        oldActiveElement.element.blur();
        }
    } catch (StaleElementReferenceException ex) {
      // old element has gone, do nothing
    }
    element.focus();
}

โดยไม่ต้องอัปเดตเป็น 2.23.0 หรือใหม่กว่าคุณสามารถให้องค์ประกอบใด ๆ กับโฟกัสของหน้าเว็บได้ ฉันเพิ่งใช้element.click()ตัวอย่าง


1
ว้าว ... นี่คือการหาปิดบังจริงๆทำงานดี .. ตอนนี้ผมสงสัยว่าถ้าไดรเวอร์อื่น ๆ (เช่น chromedriver) มีปัญหาที่คล้ายกันเกินไป
kevlarr

0

เพิ่งเกิดขึ้นกับฉันเมื่อพยายาม send_keys ไปยังกล่องอินพุตการค้นหา - ที่มีการอัปเดตอัตโนมัติขึ้นอยู่กับสิ่งที่คุณพิมพ์ Eero ดังกล่าวโดย Eero สิ่งนี้อาจเกิดขึ้นได้หากองค์ประกอบของคุณทำการปรับปรุง Ajax ในขณะที่คุณพิมพ์ข้อความของคุณ . การแก้ปัญหาคือการส่งตัวละครตัวหนึ่งที่เวลาและค้นหาอีกครั้งสำหรับองค์ประกอบเข้า (ตัวอย่างเป็นทับทิมที่แสดงด้านล่าง)

def send_keys_eachchar(webdriver, elem_locator, text_to_send)
  text_to_send.each_char do |char|
    input_elem = webdriver.find_element(elem_locator)
    input_elem.send_keys(char)
  end
end

0

เพื่อเพิ่มคำตอบของ @ jarib ฉันได้ทำวิธีการขยายหลายวิธีซึ่งช่วยกำจัดสภาพการแข่งขัน

นี่คือการตั้งค่าของฉัน:

ฉันมีคลาสที่เรียกว่า "Driver.cs" มันมีระดับคงที่เต็มรูปแบบของวิธีการขยายสำหรับไดรเวอร์และฟังก์ชั่นคงที่มีประโยชน์อื่น ๆ

สำหรับองค์ประกอบที่ฉันต้องการค้นคืนฉันสร้างวิธีการขยายแบบต่อไปนี้:

public static IWebElement SpecificElementToGet(this IWebDriver driver) {
    return driver.FindElement(By.SomeSelector("SelectorText"));
}

สิ่งนี้ช่วยให้คุณสามารถดึงองค์ประกอบนั้นจากคลาสทดสอบใด ๆ ด้วยรหัส:

driver.SpecificElementToGet();

ตอนนี้ถ้าผลลัพธ์เป็น a StaleElementReferenceException, ฉันมีวิธีคงที่ต่อไปนี้ในคลาสไดรเวอร์ของฉัน:

public static void WaitForDisplayed(Func<IWebElement> getWebElement, int timeOut)
{
    for (int second = 0; ; second++)
    {
        if (second >= timeOut) Assert.Fail("timeout");
        try
        {
            if (getWebElement().Displayed) break;
        }
        catch (Exception)
        { }
        Thread.Sleep(1000);
    }
}

พารามิเตอร์แรกของฟังก์ชันนี้คือฟังก์ชันใด ๆ ที่ส่งคืนออบเจ็กต์ IWebElement พารามิเตอร์ที่สองคือการหมดเวลาในหน่วยวินาที (รหัสสำหรับการหมดเวลาถูกคัดลอกจาก Selenium IDE สำหรับ FireFox) รหัสสามารถใช้เพื่อหลีกเลี่ยงข้อยกเว้นองค์ประกอบเก่าด้วยวิธีต่อไปนี้:

MyTestDriver.WaitForDisplayed(driver.SpecificElementToGet,5);

โค้ดด้านบนจะโทรออกdriver.SpecificElementToGet().Displayedไปจนกว่าจะdriver.SpecificElementToGet()ไม่มีข้อยกเว้นและ.Displayedประเมินtrueและ 5 วินาทีไม่ได้ผ่าน หลังจาก 5 วินาทีการทดสอบจะล้มเหลว

ที่ด้านพลิกเพื่อรอองค์ประกอบที่ไม่ได้อยู่คุณสามารถใช้ฟังก์ชั่นต่อไปนี้ในลักษณะเดียวกัน:

public static void WaitForNotPresent(Func<IWebElement> getWebElement, int timeOut) {
    for (int second = 0;; second++) {
        if (second >= timeOut) Assert.Fail("timeout");
            try
            {
                if (!getWebElement().Displayed) break;
            }
            catch (ElementNotVisibleException) { break; }
            catch (NoSuchElementException) { break; }
            catch (StaleElementReferenceException) { break; }
            catch (Exception)
            { }
            Thread.Sleep(1000);
        }
}

0

ฉันคิดว่าฉันพบวิธีที่สะดวกในการจัดการ StaleElementReferenceException โดยปกติคุณจะต้องเขียน wrappers สำหรับวิธี WebElement ทุกวิธีเพื่อลองดำเนินการอีกครั้งซึ่งน่าหงุดหงิดและเสียเวลามากมาย

เพิ่มรหัสนี้

webDriverWait.until((webDriver1) -> (((JavascriptExecutor) webDriver).executeScript("return document.readyState").equals("complete")));

if ((Boolean) ((JavascriptExecutor) webDriver).executeScript("return window.jQuery != undefined")) {
    webDriverWait.until((webDriver1) -> (((JavascriptExecutor) webDriver).executeScript("return jQuery.active == 0")));
}

ก่อนที่ทุกการกระทำของ WebElement จะช่วยเพิ่มความเสถียรของการทดสอบของคุณ แต่คุณยังสามารถรับ StaleElementReferenceException ได้เป็นครั้งคราว

ดังนั้นนี่คือสิ่งที่ฉันมาด้วย (ใช้ AspectJ):

package path.to.your.aspects;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.RemoteWebElement;
import org.openqa.selenium.support.pagefactory.DefaultElementLocator;
import org.openqa.selenium.support.pagefactory.internal.LocatingElementHandler;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

@Aspect
public class WebElementAspect {
    private static final Logger LOG = LogManager.getLogger(WebElementAspect.class);
    /**
     * Get your WebDriver instance from some kind of manager
     */
    private WebDriver webDriver = DriverManager.getWebDriver();
    private WebDriverWait webDriverWait = new WebDriverWait(webDriver, 10);

    /**
     * This will intercept execution of all methods from WebElement interface
     */
    @Pointcut("execution(* org.openqa.selenium.WebElement.*(..))")
    public void webElementMethods() {}

    /**
     * @Around annotation means that you can insert additional logic
     * before and after execution of the method
     */
    @Around("webElementMethods()")
    public Object webElementHandler(ProceedingJoinPoint joinPoint) throws Throwable {
        /**
         * Waiting until JavaScript and jQuery complete their stuff
         */
        waitUntilPageIsLoaded();

        /**
         * Getting WebElement instance, method, arguments
         */
        WebElement webElement = (WebElement) joinPoint.getThis();
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        Object[] args = joinPoint.getArgs();

        /**
         * Do some logging if you feel like it
         */
        String methodName = method.getName();

        if (methodName.contains("click")) {
            LOG.info("Clicking on " + getBy(webElement));
        } else if (methodName.contains("select")) {
            LOG.info("Selecting from " + getBy(webElement));
        } else if (methodName.contains("sendKeys")) {
            LOG.info("Entering " + args[0].toString() + " into " + getBy(webElement));
        }

        try {
            /**
             * Executing WebElement method
             */
            return joinPoint.proceed();
        } catch (StaleElementReferenceException ex) {
            LOG.debug("Intercepted StaleElementReferenceException");

            /**
             * Refreshing WebElement
             * You can use implementation from this blog
             * http://www.sahajamit.com/post/mystery-of-stale-element-reference-exception/
             * but remove staleness check in the beginning (if(!isElementStale(elem))), because we already caught exception
             * and it will result in an endless loop
             */
            webElement = StaleElementUtil.refreshElement(webElement);

            /**
             * Executing method once again on the refreshed WebElement and returning result
             */
            return method.invoke(webElement, args);
        }
    }

    private void waitUntilPageIsLoaded() {
        webDriverWait.until((webDriver1) -> (((JavascriptExecutor) webDriver).executeScript("return document.readyState").equals("complete")));

        if ((Boolean) ((JavascriptExecutor) webDriver).executeScript("return window.jQuery != undefined")) {
            webDriverWait.until((webDriver1) -> (((JavascriptExecutor) webDriver).executeScript("return jQuery.active == 0")));
        }
    }

    private static String getBy(WebElement webElement) {
        try {
            if (webElement instanceof RemoteWebElement) {
                try {
                    Field foundBy = webElement.getClass().getDeclaredField("foundBy");
                    foundBy.setAccessible(true);
                    return (String) foundBy.get(webElement);
                } catch (NoSuchFieldException e) {
                    e.printStackTrace();
                }
            } else {
                LocatingElementHandler handler = (LocatingElementHandler) Proxy.getInvocationHandler(webElement);

                Field locatorField = handler.getClass().getDeclaredField("locator");
                locatorField.setAccessible(true);

                DefaultElementLocator locator = (DefaultElementLocator) locatorField.get(handler);

                Field byField = locator.getClass().getDeclaredField("by");
                byField.setAccessible(true);

                return byField.get(locator).toString();
            }
        } catch (IllegalAccessException | NoSuchFieldException e) {
            e.printStackTrace();
        }

        return null;
    }
}

หากต้องการเปิดใช้งานมุมมองนี้ให้สร้างไฟล์ src\main\resources\META-INF\aop-ajc.xml และเขียน

<aspectj>
    <aspects>
        <aspect name="path.to.your.aspects.WebElementAspect"/>
    </aspects>
</aspectj>

เพิ่มไปยังของคุณ pom.xml

<properties>
    <aspectj.version>1.9.1</aspectj.version>
</properties>

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.22.0</version>
            <configuration>
                <argLine>
                    -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"
                </argLine>
            </configuration>
            <dependencies>
                <dependency>
                    <groupId>org.aspectj</groupId>
                    <artifactId>aspectjweaver</artifactId>
                    <version>${aspectj.version}</version>
                </dependency>
            </dependencies>
        </plugin>
</build>

และนั่นคือทั้งหมด หวังว่ามันจะช่วย


0

คุณสามารถแก้ปัญหานี้ได้โดยใช้การรออย่างชัดเจนเพื่อที่คุณจะได้ไม่ต้องรออย่างหนัก

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

List<WebElement> elements = driver.findElements("Object property");
for(WebElement element:elements)
{
    new WebDriverWait(driver,10).until(ExpectedConditions.presenceOfAllElementsLocatedBy("Object property"));
    element.click();//or any other action
}

หรือสำหรับองค์ประกอบเดียวคุณสามารถใช้รหัสด้านล่าง

new WebDriverWait(driver,10).until(ExpectedConditions.presenceOfAllElementsLocatedBy("Your object property"));
driver.findElement("Your object property").click();//or anyother action 


-5
FirefoxDriver _driver = new FirefoxDriver();

// create webdriverwait
WebDriverWait wait = new WebDriverWait(_driver, TimeSpan.FromSeconds(10));

// create flag/checker
bool result = false;

// wait for the element.
IWebElement elem = wait.Until(x => x.FindElement(By.Id("Element_ID")));

do
{
    try
    {
        // let the driver look for the element again.
        elem = _driver.FindElement(By.Id("Element_ID"));

        // do your actions.
        elem.SendKeys("text");

        // it will throw an exception if the element is not in the dom or not
        // found but if it didn't, our result will be changed to true.
        result = !result;
    }
    catch (Exception) { }
} while (result != true); // this will continue to look for the element until
                          // it ends throwing exception.

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

ยินดีต้อนรับสู่ stackoverflow! เป็นการดีกว่าเสมอที่จะให้คำอธิบายสั้น ๆ สำหรับโค้ดตัวอย่างเพื่อปรับปรุงความถูกต้องของการโพสต์ :)
Picrofo Software

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