웹 UI 자동화 테스트에서 페이지 요소 만료 처리

먼저 코드를 입력하십시오.

package ec.qa.autotest.ui.common.action;

import java.util.List;
import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindAll;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.PageFactory;
import org.openqa.selenium.support.ui.SystemClock;
import org.testng.Assert;

import ec.qa.autotest.ui.custom.annotation.PageObject;
import ec.qa.autotest.ui.testbase.TestBase;

@PageObject
public class AdminLoadingProgress {

	@FindAll({ @FindBy(xpath = "//body/div") })
	private List<WebElement> elementsCol;
	private String LOADINGGIF_XPATH = "//body/div[@class='modal-backdrop fade in']";
	private String LOADINGGIF_CLASS = "modal-backdrop fade in";

	public AdminLoadingProgress() {
		PageFactory.initElements(TestBase.getWebDriver(), this);
	}

	public void wiatForLoadingTOComplete() throws InterruptedException {
		Assert.assertEquals(waitForLoadingGIFToDisappear(5000), true);
	}

	public void wiatForLoadingTOComplete(long timeOut) throws InterruptedException {
		Assert.assertEquals(waitForLoadingGIFToDisappear(timeOut), true);
	}

	/**
	 * @author xin.wang
	 * @see   loading gif   
	 */
	//       DIV  
	private boolean waitForLoadingGIFToDisappear(long timeOut) throws InterruptedException {
		TestBase.getWebDriver().findElement(By.xpath(LOADINGGIF_XPATH));
		System.out.println("==     ....==");
		SystemClock sc =new SystemClock();
		for (WebElement e : elementsCol) {
			try {
				if (e.getAttribute("class").equals(LOADINGGIF_CLASS)) {
					long endTime = sc.laterBy(timeOut);
					while (sc.isNowBefore(endTime)) {
						if (!elementsCol.contains(e)) {
							System.out.println("==       !==");
							return true;
						}
						TimeUnit.MICROSECONDS.sleep(300);
					}
					return false;
				}
			} catch (StaleElementReferenceException se) {
				System.out.println("==       ==");
			}
		}
		System.out.println("==       !==");
		return true;
	}
}

테스트 대상 페이지는 데이터를 로드할 때 현재 DOM에 DIV[
/body/div[@class='modal-backdrop fade in']
블록, 이 DIV는 페이지에 GIF 그림을 보여 줍니다. 사용자 페이지에서 데이터를 불러오고 있음을 알려 줍니다. 데이터 불러오기가 완료되면 (document.ready State='completed') 페이지의 JS는 이 DIV를 현재 DOM에서 제거합니다. (좀 이상합니다. 일반적인 방법은 이 DIV에 CSS의 디스플레이 속성을 추가하면 됩니다.) 자동 테스트를 한 후에 페이지가 만료되는 문제가 발생할 수 있습니다.나중에 스스로 연구한 결과 LOADINGIF가 사라지기를 기다렸던 방법을 바꾸고 기한이 지났을 때 알림 문자를 출력했다. 200번 반복해서 이 통용적인 방법을 사용한 Test Case를 돌아다녔는데 예시적으로 원소가 기한이 지났다는 이상이 나타나지 않았다. 그러나 JENkins의 컨트롤러에서 출력하면 원소가 기한이 지났다는 문제를 볼 수 있다. 그러나 이 방법은 이미 이 이상을 잡고 처리했다.
다음과 같은 Jenkins의 콘솔 정보:
Starting ChromeDriver 2.20.353145 (343b531d31eeb933ec778dbcf7081628a1396067) on port 29987Only local connections are allowed.
==     ...
.==       
       =
=       !==

사실 기한이 지나고 이상한 문장이 나오는 것은 이 문장이다.
e.getAttribute("class").equals(LOADINGGIF_CLASS)
  
만료 원인 분석: LOADINGGIF의 DIV가 사라져서 현재 이 DIV 요소를 인용한 인용 e가 효력을 상실하기 때문에 웹드라이브가 던집니다
StaleElementReferenceException
유난히
, GIF가 사라진 이상 내가 원하는 결과야.
사실 위의 만료 문제가 거의 발생하지 않았습니다. 적어도 300개 정도의 CASE를 실행한 적이 1-2번밖에 없습니다.
Tests run: 203, Failures: 1, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------[INFO] 
BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 01:34 h

그러나 이것은 자동화 테스트의 불안정한 상황에 속하기 때문에 가능한 한 처리하고 가능한 한 테스트 결과의 정확성을 확보해야 한다. 
Selenium 공식 홈페이지의 설명:

Stale Element Reference Exception


You have probably been directed to this page because you've seen a StaleElementReferenceException in your tests.

Common Causes


A stale element reference exception is thrown in one of two cases, the first being more common than the second:
The element has been deleted entirely.
The element is no longer attached to the DOM.

The Element has been Deleted


The most frequent cause of this is that page that the element was part of has been refreshed, or the user has navigated away to another page. A less common, but still common cause is where a JS library has deleted an element and replaced it with one with the same ID or attributes. In this case, although the replacement elements may look identical they are different; the driver has no way to determine that the replacements are actually what's expected.
If the element has been replaced with an identical one, a useful strategy is to look up the element again. If you do this automatically, be aware that you may well be opening your tests to a race condition and potential flakiness. For example, given the code: WebElement element = driver.findElement(By.id("example"));String text = element.getText();
If "element.getText"returns before the element is removed from the DOM you'll get one result. If, however, the element is removed from the DOM and your code does an automatic lookup for the element again before "element.getText"a different result may be returned.
Should you wish to head down this route, the simplest hook point is to call setElementConverter.

The Element is not Attached to the DOM


A common technique used for simulating a tabbed UI in a web app is to prepare DIVs for each tab, but only attach one at a time, storing the rest in variables. In this case, it's entirely possible that your code might have a reference to an element that is no longer attached to the DOM (that is, that has an ancestor which is "document.documentElement").
If WebDriver throws a stale element exception in this case, even though the element still exists, the reference is lost. You should discard the current reference you hold and replace it, possibly by locating the element again once it is attached to the DOM.

Edge Cases


The element changes type, but keeps the same locator sematics (JQuery and others)

The element changes type, but keeps the same locator sematics (JQuery and others)


Watermarked fields in JQuery change from a regular input to a password field as they get focus. The first end-user key press arrives in the password variant. Refer to pwField2 in
  this example

좋은 웹페이지 즐겨찾기