সেলেনিয়ামে কীভাবে "স্টলেএলিমেন্টরিফেকশন এক্সপ্লেশন" এড়ানো যায়?


89

আমি জাভা ব্যবহার করে প্রচুর সেলেনিয়াম পরীক্ষা বাস্তবায়ন করছি। কখনও কখনও, আমার পরীক্ষাগুলি a এর কারণে ব্যর্থ হয় StaleElementReferenceException। আপনি পরীক্ষা আরও স্থিতিশীল করার জন্য কিছু পদ্ধতির পরামর্শ দিতে পারেন?

উত্তর:


91

পৃষ্ঠায় কোনও ডিওএম অপারেশন অস্থায়ীভাবে উপাদানটির অ্যাক্সেসযোগ্য হয়ে যাওয়ার কারণে এটি ঘটতে পারে। এই ক্ষেত্রেগুলিতে অনুমতি দেওয়ার জন্য, অবশেষে একটি ব্যতিক্রম ছোঁড়ার আগে আপনি লুপে বেশ কয়েকবার উপাদানটি অ্যাক্সেস করার চেষ্টা করতে পারেন।

ব্যবহার করে দেখুন darrelgrainger.blogspot.com থেকে এই চমৎকার সমাধান :

public boolean retryingFindClick(By by) {
    boolean result = false;
    int attempts = 0;
    while(attempts < 2) {
        try {
            driver.findElement(by).click();
            result = true;
            break;
        } catch(StaleElementException e) {
        }
        attempts++;
    }
    return result;
}

4
কি দারুন! এটি কেবল আমার প্রয়োজন ছিল। ধন্যবাদ!
স্পার্টা সিক্সেরো

4
এটি উপাদানটির বিভিন্ন রেফারেন্স ব্যবহার করেও ঠিক করা যেতে পারে।
রিপন আল ওয়াসিম

@jspcal, এটি আমার জন্য আকর্ষণীয় কাজ করেছে! অনেক ধন্যবাদ!
অ্যান্থনি ওকোথ

যদি উপরের বিষয়গুলি এটি সমাধান না করে, সর্বশেষ ক্রোমড্রাইভারে আপডেট করা আমাদের জন্য এটি সমাধান করে।
ভিডেক্স

4
এটি অনেক উপায়ে ভয়ঙ্কর is এটি আমার বর্তমান সমস্যার সমাধান করে, তাই ধন্যবাদ।
সফটওয়্যার ইঞ্জিনিয়ার

68

আমি মাঝে মাঝে এই সমস্যাটি নিয়ে আসছিলাম। আমার অজানা, ব্যাকবোনজেএস পৃষ্ঠায় চলছে এবং আমি ক্লিক করতে চেষ্টা করছি এমন উপাদানটির পরিবর্তে। আমার কোডটি এরকম দেখাচ্ছে।

driver.findElement(By.id("checkoutLink")).click();

যা অবশ্যই কার্যকরীভাবে এটির মতো।

WebElement checkoutLink = driver.findElement(By.id("checkoutLink"));
checkoutLink.click();

জাভাস্ক্রিপ্ট চেকআউটলিংক উপাদানটি এটি সন্ধান এবং ক্লিক করার মধ্যে প্রতিস্থাপন করবে তা হ'ল মাঝেমধ্যে ঘটবে, অর্থাত্‍।

WebElement checkoutLink = driver.findElement(By.id("checkoutLink"));
// javascript replaces checkoutLink
checkoutLink.click();

লিঙ্কটি ক্লিক করার চেষ্টা করার সময় যা যথাযথভাবে একটি স্ট্যালিলিমেন্টরিফেকশন অনুভবের দিকে পরিচালিত করে। ওয়েবড্রাইভারকে জাভাস্ক্রিপ্টটি শেষ না হওয়া পর্যন্ত অপেক্ষা করতে বলার কোনও নির্ভরযোগ্য উপায় আমি খুঁজে পাইনি, সুতরাং আমি কীভাবে শেষ পর্যন্ত এটি সমাধান করেছি তা এখানে।

new WebDriverWait(driver, timeout)
    .ignoring(StaleElementReferenceException.class)
    .until(new Predicate<WebDriver>() {
        @Override
        public boolean apply(@Nullable WebDriver driver) {
            driver.findElement(By.id("checkoutLink")).click();
            return true;
        }
    });

ক্লিকটি সাফল্য না পাওয়ানো বা টাইমআউট না পৌঁছানো পর্যন্ত এই কোডটি নিয়মিত ক্লিক করে স্টেইলিমেন্টরিফেরেন্স এক্সেপশন উপেক্ষা করে লিঙ্কটি ক্লিক করার চেষ্টা করবে। আমি এই সমাধানটি পছন্দ করি কারণ এটি আপনাকে যে কোনও পুনরায় চেষ্টা করার যুক্তি লিখতে বাঁচায় এবং কেবল ওয়েবড্রাইভারের অন্তর্নির্মিত নির্মাণগুলি ব্যবহার করে।


এই উত্তর অবচয় করা হয়েছে।
বৈভবকুল20

20

সাধারণত এটি ডিওএম আপডেট হওয়ার কারণে হয় এবং আপনি কোনও আপডেট / নতুন উপাদান অ্যাক্সেস করার চেষ্টা করছেন - তবে ডম এর রিফ্রেশ যাতে এটি আপনার একটি অবৈধ রেফারেন্স ..

আপডেটটি সম্পূর্ণ হয়েছে তা নিশ্চিত করতে প্রথমে উপাদানটির একটি সুস্পষ্ট অপেক্ষা ব্যবহার করে এটিকে ঘিরে ধরুন, তারপরে আবার উপাদানটির একটি নতুন রেফারেন্স ধরুন।

চিত্রিত করার জন্য এখানে কয়েকটি স্যুইডো কোড দেওয়া হয়েছে (আমি এই সমস্যাটির জন্য আমি ব্যবহার করি কিছু সি # কোড থেকে গৃহীত ):

WebDriverWait wait = new WebDriverWait(browser, TimeSpan.FromSeconds(10));
IWebElement aRow = browser.FindElement(By.XPath(SOME XPATH HERE);
IWebElement editLink = aRow.FindElement(By.LinkText("Edit"));

//this Click causes an AJAX call
editLink.Click();

//must first wait for the call to complete
wait.Until(ExpectedConditions.ElementExists(By.XPath(SOME XPATH HERE));

//you've lost the reference to the row; you must grab it again.
aRow = browser.FindElement(By.XPath(SOME XPATH HERE);

//now proceed with asserts or other actions.

আশাকরি এটা সাহায্য করবে!


17

কেনির সমাধানটি ভাল, তবে এটি আরও মার্জিত উপায়ে লেখা যেতে পারে

new WebDriverWait(driver, timeout)
        .ignoring(StaleElementReferenceException.class)
        .until((WebDriver d) -> {
            d.findElement(By.id("checkoutLink")).click();
            return true;
        });

বা এছাড়াও:

new WebDriverWait(driver, timeout).ignoring(StaleElementReferenceException.class).until(ExpectedConditions.elementToBeClickable(By.id("checkoutLink")));
driver.findElement(By.id("checkoutLink")).click();

তবে যাইহোক, সেরা সমাধান হ'ল সেলেনাইড গ্রন্থাগারের উপর নির্ভর করা, এটি এই ধরণের জিনিস এবং আরও অনেক কিছু পরিচালনা করে। (উপাদানগুলির উল্লেখগুলির পরিবর্তে এটি প্রক্সিগুলি পরিচালনা করে যাতে আপনার কখনও বাসি উপাদানগুলির সাথে ডিল করতে হবে না, যা বেশ কঠিন হতে পারে)। সেলেনাইড



আপনার দ্বিতীয় সমাধানটি কাজ করবে কারণ আপনি যখন এটি খুঁজে পাবেন না তখন উপাদানটি ক্লিক করলে এটি সিঁড়ি দিয়ে যায়।
রাজাগোপালান

এই সমস্যাটি এড়াতে সেলেনাইড ব্যবহার করুন, আরও সহজ। সেলেনিয়ামটি এই সমস্যাটির কারণে এবং সরল ব্যবহারকারীর জন্য নিম্ন স্তরের এপিআই হ'ল একাকী ব্যবহৃত হওয়ার অর্থ নয়
কোকরোসেলো

আমি পুরোপুরি সচেতন। আমি WATIR ব্যবহার করছি যা রুবি সেলেনিয়াম বাইন্ডিংয়ের চারপাশে একটি মোড়ক, ওয়াটির স্বয়ংক্রিয়ভাবে এই সমস্ত সমস্যার যত্ন নেয় (উদাহরণস্বরূপ বাসি উপাদানটির জন্য)। আমি জাভা বাইন্ডিংয়ের সমতুল্য কিছু সন্ধান করছি, আমি সেলেনাইড পেয়েছি তবে সেলেনাইডে কীভাবে অন্তর্নিহিত অপেক্ষার এবং সুস্পষ্ট অপেক্ষা পরিবর্তন করতে হবে তা আমি জানি না। আপনি কি করতে পারেন আমাকে তা করতে পারেন? বা এমন কোনও উপাদান রয়েছে যেখানে আপনি আমাকে প্রস্তাব করতে পারেন যেখানে আমি উল্লেখ করতে পারি? এবং ফ্লুটলেনিয়াম সম্পর্কে আপনার মতামত কী?
রাজাগোপালন

4
লোকেরা জেনে রাখা উচিত যে ওপি দ্বারা নির্বাচিত উত্তরটি ২০১২ সাল পর্যন্ত রয়েছে। বিগত years বছরে অনেক কিছুই পরিবর্তিত হয়েছে। এই উত্তরটি 2019 এর জন্য আরও সঠিক
hfontanez

11

এর কারণটি StaleElementReferenceExceptionইতিমধ্যে নির্ধারণ করা হয়েছে: উপাদানটির সাথে কিছু খুঁজে পাওয়া এবং করার মধ্যে ডিওএম-এ আপডেট।

ক্লিক-সমস্যার জন্য আমি সম্প্রতি এর মতো একটি সমাধান ব্যবহার করেছি:

public void clickOn(By locator, WebDriver driver, int timeout)
{
    final WebDriverWait wait = new WebDriverWait(driver, timeout);
    wait.until(ExpectedConditions.refreshed(
        ExpectedConditions.elementToBeClickable(locator)));
    driver.findElement(locator).click();
}

গুরুত্বপূর্ণ অংশটি হল সেলেনিয়ামের নিজস্ব ExpectedConditionsমাধ্যমে "চেইনিং" ExpectedConditions.refreshed()। এটি প্রকৃতপক্ষে অপেক্ষা করে এবং পরীক্ষিত উপাদানগুলিকে নির্দিষ্ট সময়সীমা চলাকালীন রিফ্রেশ করা হয়েছে কিনা তা পরীক্ষা করে এবং অতিরিক্তভাবে উপাদানটি ক্লিকযোগ্য হয়ে ওঠার জন্য অপেক্ষা করে।

রিফ্রেশ পদ্ধতির জন্য ডকুমেন্টেশনটি দেখুন ।


4

আমার প্রকল্পে আমি স্টেবলওয়েলেমেন্টের একটি ধারণা চালু করি। এটি ওয়েবএলিমেন্টের জন্য একটি মোড়ক যা উপাদানটি বাসি কিনা তা সনাক্ত করতে সক্ষম এবং মূল উপাদানটির জন্য একটি নতুন রেফারেন্স সন্ধান করতে সক্ষম। আমি এমন উপাদানগুলির সনাক্তকরণের জন্য একটি সহায়ক পদ্ধতি যুক্ত করেছি যা ওয়েবএলিমেন্টের পরিবর্তে স্ট্যাবলওয়েলেমেন্ট ফিরিয়ে দেয় এবং স্ট্যালিলেমেন্টরিফারেন্স সহ সমস্যাটি অদৃশ্য হয়ে গেল।

public static IStableWebElement FindStableElement(this ISearchContext context, By by)
{
    var element = context.FindElement(by);
    return new StableWebElement(context, element, by, SearchApproachType.First);
} 

সি # তে কোডটি আমার প্রকল্পের পৃষ্ঠায় উপলভ্য তবে এটি জাভা https://github.com/cezarypiatek/Telllurium/blob/master/Src/MvcPages/SeleniumUtils/StableWebElement.cs এ সহজেই পোর্ট করা যায় could


1

সি # তে একটি সমাধান হবে:

সহায়ক শ্রেণি:

internal class DriverHelper
{

    private IWebDriver Driver { get; set; }
    private WebDriverWait Wait { get; set; }

    public DriverHelper(string driverUrl, int timeoutInSeconds)
    {
        Driver = new ChromeDriver();
        Driver.Url = driverUrl;
        Wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(timeoutInSeconds));
    }

    internal bool ClickElement(string cssSelector)
    {
        //Find the element
        IWebElement element = Wait.Until(d=>ExpectedConditions.ElementIsVisible(By.CssSelector(cssSelector)))(Driver);
        return Wait.Until(c => ClickElement(element, cssSelector));
    }

    private bool ClickElement(IWebElement element, string cssSelector)
    {
        try
        {
            //Check if element is still included in the dom
            //If the element has changed a the OpenQA.Selenium.StaleElementReferenceException is thrown.
            bool isDisplayed = element.Displayed;

            element.Click();
            return true;
        }
        catch (StaleElementReferenceException)
        {
            //wait until the element is visible again
            element = Wait.Until(d => ExpectedConditions.ElementIsVisible(By.CssSelector(cssSelector)))(Driver);
            return ClickElement(element, cssSelector);
        }
        catch (Exception)
        {
            return false;
        }
    }
}

প্রার্থনা:

        DriverHelper driverHelper = new DriverHelper("http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp", 10);
        driverHelper.ClickElement("input[value='csharp']:first-child");

একইভাবে জাভা জন্য ব্যবহার করা যেতে পারে।


1

কেনির সমাধানটি হ্রাস পেয়েছে এটি ব্যবহার করে, আমি ডাবল ক্লিক করতে ক্রিয়া শ্রেণি ব্যবহার করছি তবে আপনি কিছু করতে পারেন।

new FluentWait<>(driver).withTimeout(30, TimeUnit.SECONDS).pollingEvery(5, TimeUnit.SECONDS)
                    .ignoring(StaleElementReferenceException.class)
                    .until(new Function() {

                    @Override
                    public Object apply(Object arg0) {
                        WebElement e = driver.findelement(By.xpath(locatorKey));
                        Actions action = new Actions(driver);
                        action.moveToElement(e).doubleClick().perform();
                        return true;
                    }
                });

1

findByAndroidIdনিখুঁতভাবে পরিচালনা করে এমন পরিষ্কার পদ্ধতি StaleElementReference

এটি jspcal এর উত্তরের উপর ভিত্তি করে তৈরি হয়েছে তবে এটি আমাদের সেটআপটি দিয়ে পরিষ্কারভাবে কাজ করার জন্য আমাকে উত্তরটি সংশোধন করতে হয়েছিল এবং তাই অন্যের পক্ষে সহায়ক হলে আমি এটিকে এখানে যুক্ত করতে চেয়েছিলাম। যদি এই উত্তরটি আপনাকে সহায়তা করে, দয়া করে jspcal এর উত্তরটি উপুড় করুন

// This loops gracefully handles StateElementReference errors and retries up to 10 times. These can occur when an element, like a modal or notification, is no longer available.
export async function findByAndroidId( id, { assert = wd.asserters.isDisplayed, timeout = 10000, interval = 100 } = {} ) {
  MAX_ATTEMPTS = 10;
  let attempt = 0;

  while( attempt < MAX_ATTEMPTS ) {
    try {
      return await this.waitForElementById( `android:id/${ id }`, assert, timeout, interval );
    }
    catch ( error ) {
      if ( error.message.includes( "StaleElementReference" ) )
        attempt++;
      else
        throw error; // Re-throws the error so the test fails as normal if the assertion fails.
    }
  }
}

0

এটি সি # ব্যবহার করে আমার জন্য (100% কাজ করছে) কাজ করে

public Boolean RetryingFindClick(IWebElement webElement)
    {
        Boolean result = false;
        int attempts = 0;
        while (attempts < 2)
        {
            try
            {
                webElement.Click();
                result = true;
                break;
            }
            catch (StaleElementReferenceException e)
            {
                Logging.Text(e.Message);
            }
            attempts++;
        }
        return result;
    }

0

সমস্যাটি যখন আপনি জাভাস্ক্রিপ্ট থেকে জাভাতে জাভাস্ক্রিপ্টে ফিরে এলিমেন্টটি পাস করেন তখন এটি DOM ছাড়তে পারে।
জাভাস্ক্রিপ্টে পুরো জিনিসটি করার চেষ্টা করুন:

driver.executeScript("document.querySelector('#my_id').click()") 

0

এটা চেষ্টা কর

while (true) { // loops forever until break
    try { // checks code for exceptions
        WebElement ele=
        (WebElement)wait.until(ExpectedConditions.elementToBeClickable((By.xpath(Xpath))));  
        break; // if no exceptions breaks out of loop
    } 
    catch (org.openqa.selenium.StaleElementReferenceException e1) { 
        Thread.sleep(3000); // you can set your value here maybe 2 secs
        continue; // continues to loop if exception is found
    }
}

0

আমি এখানে সমাধান খুঁজে পেয়েছি । আমার ক্ষেত্রে বর্তমান উইন্ডো, ট্যাব বা পৃষ্ঠা রেখে আবার ফিরে আসার ক্ষেত্রে উপাদান অ্যাক্সেসযোগ্য হয়ে যায়।

.ignore (StaleElement ...), .refreshed (...) এবং উপাদানToBeClicable (...) সাহায্য করেনি এবং আমি act.doubleClick(element).build().perform();স্ট্রিংয়ে ব্যতিক্রম পাচ্ছি ।

আমার প্রধান পরীক্ষার শ্রেণিতে ফাংশন ব্যবহার করে:

openForm(someXpath);

আমার বেসস্টেস্ট ফাংশন:

int defaultTime = 15;

boolean openForm(String myXpath) throws Exception {
    int count = 0;
    boolean clicked = false;
    while (count < 4 || !clicked) {
        try {
            WebElement element = getWebElClickable(myXpath,defaultTime);
            act.doubleClick(element).build().perform();
            clicked = true;
            print("Element have been clicked!");
            break;
        } catch (StaleElementReferenceException sere) {
            sere.toString();
            print("Trying to recover from: "+sere.getMessage());
            count=count+1;
        }
    }

আমার বেসক্লাস ফাংশন:

protected WebElement getWebElClickable(String xpath, int waitSeconds) {
        wait = new WebDriverWait(driver, waitSeconds);
        return wait.ignoring(StaleElementReferenceException.class).until(
                ExpectedConditions.refreshed(ExpectedConditions.elementToBeClickable(By.xpath(xpath))));
    }

0

একটি সম্ভাব্য সমস্যা থাকতে পারে যা স্ট্যালিলিমেন্টরিফেকশন অনুভবের দিকে নিয়ে যায় যা এখন পর্যন্ত কেউ উল্লেখ করেনি (ক্রিয়া সম্পর্কিত)।

আমি এটি জাভাস্ক্রিপ্টে ব্যাখ্যা করি, তবে জাভাতে এটি একই।

এটি কাজ করবে না:

let actions = driver.actions({ bridge: true })
let a = await driver.findElement(By.css('#a'))
await actions.click(a).perform() // this leads to a DOM change, #b will be removed and added again to the DOM.
let b = await driver.findElement(By.css('#b'))
await actions.click(b).perform()

তবে ক্রিয়াগুলি আবার ইনস্ট্যান্ট করলে তা সমাধান হবে:

let actions = driver.actions({ bridge: true })
let a = await driver.findElement(By.css('#a'))
await actions.click(a).perform()  // this leads to a DOM change, #b will be removed and added again to the DOM.
actions = driver.actions({ bridge: true }) // new
let b = await driver.findElement(By.css('#b'))
await actions.click(b).perform()

0

সাধারণত স্টলেএলিমেন্টরিফারেন্সএক্সেপশন যখন আমরা অ্যাক্সেস করার চেষ্টা করি তখন উপস্থিত হয় তবে অন্যান্য উপাদানগুলি আমাদের আগ্রহী সেই উপাদানটির অবস্থানকে প্রভাবিত করতে পারে তাই আমরা ক্লিক করতে বা গেটটেক্সট বা ওয়েবএলেমে কিছু ব্যবস্থা নেওয়ার চেষ্টা করি আমরা ব্যতিক্রম পাই যা সাধারণত বলে যে উপাদানটি ডিওএমের সাথে সংযুক্ত না থাকে says ।

সমাধানটি আমি চেষ্টা করেছিলাম:

 protected void clickOnElement(By by) {
        try {
            waitForElementToBeClickableBy(by).click();
        } catch (StaleElementReferenceException e) {
            for (int attempts = 1; attempts < 100; attempts++) {
                try {
                    waitFor(500);
                    logger.info("Stale element found retrying:" + attempts);
                    waitForElementToBeClickableBy(by).click();
                    break;
                } catch (StaleElementReferenceException e1) {
                    logger.info("Stale element found retrying:" + attempts);
                }
            }
        }

protected WebElement waitForElementToBeClickableBy(By by) {
        WebDriverWait wait = new WebDriverWait(getDriver(), 10);
        return wait.until(ExpectedConditions.elementToBeClickable(by));
    }

উপরের কোডে আমি প্রথমে অপেক্ষা করার চেষ্টা করি এবং তারপরে যদি ব্যতিক্রম ঘটে তবে আমি এটিকে উপাদানটিতে ক্লিক করি তবে আমি এটি ধরতে চেষ্টা করি এবং এটিকে লুপ করার চেষ্টা করি কারণ এখনও সম্ভবত সমস্ত উপাদান লোড না হওয়া এবং আবার ব্যতিক্রম ঘটতে পারে।


-4

সম্ভবত এটি আরও সম্প্রতি যুক্ত করা হয়েছিল, তবে অন্যান্য উত্তরগুলি সেলেনিয়ামের অন্তর্নিহিত অপেক্ষার বৈশিষ্ট্যটি উল্লেখ করতে ব্যর্থ হয়েছে, যা উপরের সমস্তটি আপনার জন্য করে এবং সেলেনিয়ামে অন্তর্নির্মিত।

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

findElement()উপাদানটি সন্ধান না হওয়া বা 10 সেকেন্ডের জন্য এটি পুনরায় চেষ্টা করবে ।

সূত্র - http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp



4
কেবল সংস্করণগুলিতে যে কোনও বিভ্রান্তি দূর করতে, এমনকি সেলেনিয়ামের সর্বশেষ সংস্করণেও স্পষ্টতই ওয়েট () স্ট্যালিলমেন্টরিফারেন্সএক্সসেপশনকে আটকাবে না। আমি একটি পদ্ধতি ব্যবহার করি যা সাফল্য বা নির্দিষ্ট গণনা অবধি ঘুমের সাথে লুপে ডাকে।
অ্যাঙ্গসুমান চক্রবর্তী
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.