셀레늄이 아약스 응답을 기다리도록하는 방법?
캘린더 위젯이로드되기를 기다리도록 셀레늄을 얻으려면 어떻게해야합니까? 지금 Thread.sleep(2500)
은 테스트 케이스를 junit 프로그램으로 내 보낸 후에 수행하고 있습니다.
나는 사용할 것이다
waitForElementPresent(locator)
이는 요소가 DOM에 나타날 때까지 기다립니다.
요소가 보이는지 확인해야하는 경우
waitForElementHeight(locator)
요소를 기다리는 것보다 더 일반적인 해결책은 서버에 대한 모든 연결이 닫힐 때까지 기다리는 것입니다. 이렇게하면 콜백이 없어 페이지에 영향을주지 않더라도 모든 ajax 호출이 완료 될 때까지 기다릴 수 있습니다. 자세한 내용은 여기에서 확인할 수 있습니다 .
C # 및 jQuery를 사용하여 모든 AJax 호출이 완료 될 때까지 기다리는 다음 메서드를 만들었습니다 (누군가 C #에서 JS 변수에보다 직접적으로 액세스하는 방법이 있다면 의견을 남겨주세요).
internal void WaitForAjax(int timeOut = 15)
{
var value = "";
RepeatUntil(
() => value = GetJavascriptValue("jQuery.active"),
() => value == "0",
"Ajax calls did not complete before timeout"
);
}
internal void RepeatUntil(Action repeat, Func<bool> until, string errorMessage, int timeout = 15)
{
var end = DateTime.Now + TimeSpan.FromSeconds(timeout);
var complete = false;
while (DateTime.Now < end)
{
repeat();
try
{
if (until())
{
complete = true;
break;
}
}
catch (Exception)
{ }
Thread.Sleep(500);
}
if (!complete)
throw new TimeoutException(errorMessage);
}
internal string GetJavascriptValue(string variableName)
{
var id = Guid.NewGuid().ToString();
_selenium.RunScript(String.Format(@"window.$('body').append(""<input type='text' value='""+{0}+""' id='{1}'/>"");", variableName, id));
return _selenium.GetValue(id);
}
파이썬을 사용하는 경우 버튼을 클릭하고 DOM 변경을 기다리는이 함수를 사용할 수 있습니다.
def click_n_wait(driver, button, timeout=5):
source = driver.page_source
button.click()
def compare_source(driver):
try:
return source != driver.page_source
except WebDriverException:
pass
WebDriverWait(driver, timeout).until(compare_source)
(신용 : 이 스택 오버플로 답변을 기반으로 함 )
webdriver aka selenium2를 사용하면 http://docs.seleniumhq.org/docs/04_webdriver_advanced.jsp#implicit-waits에 언급 된 암시 적 대기 구성을 사용할 수 있습니다.
Java 사용 :
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("http://somedomain/url_that_delays_loading");
WebElement myDynamicElement = driver.findElement(By.id("myDynamicElement"));
또는 파이썬 사용 :
from selenium import webdriver
ff = webdriver.Firefox()
ff.implicitly_wait(10) # seconds
ff.get("http://somedomain/url_that_delays_loading")
myDynamicElement = ff.find_element_by_id("myDynamicElement")
내 솔루션으로 다음 방법을 작성했습니다 (로드 표시기가 없었습니다).
public static void waitForAjax(WebDriver driver, String action) {
driver.manage().timeouts().setScriptTimeout(5, TimeUnit.SECONDS);
((JavascriptExecutor) driver).executeAsyncScript(
"var callback = arguments[arguments.length - 1];" +
"var xhr = new XMLHttpRequest();" +
"xhr.open('POST', '/" + action + "', true);" +
"xhr.onreadystatechange = function() {" +
" if (xhr.readyState == 4) {" +
" callback(xhr.responseText);" +
" }" +
"};" +
"xhr.send();");
}
그런 다음 실제 드라이버 로이 메서드를 호출했습니다. 이 게시물에 대한 자세한 설명 .
이것은 나를위한 일
public void waitForAjax(WebDriver driver) {
new WebDriverWait(driver, 180).until(new ExpectedCondition<Boolean>(){
public Boolean apply(WebDriver driver) {
JavascriptExecutor js = (JavascriptExecutor) driver;
return (Boolean) js.executeScript("return jQuery.active == 0");
}
});
}
비슷한 상황이 발생했습니다.로드 패널이 사라지도록 ajax 요청을 기다리고 싶었습니다. 요청 전후에 html을 검사했으며 ajax 로딩 패널에 대한 div가 있음을 발견했습니다. ajax 요청이며 요청이 끝나면 숨겨집니다. 패널이 표시 될 때까지 기다린 다음 숨길 때까지 기다리는 함수를 만들었습니다.
public void WaitForModalPanel()
{
string element_xpath = ".//*[@id='ajaxLoadingModalPanelContainer' and not(contains(@style,'display: none'))]";
WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 2, 0));
wait.Until(ExpectedConditions.ElementIsVisible(By.XPath(element_xpath)));
element_xpath = ".//*[@id='ajaxLoadingModalPanelContainer' and contains(@style,'DISPLAY: none')]";
wait.Until(ExpectedConditions.ElementExists(By.XPath(element_xpath)));
}
자세한 내용은 이것을 확인 하십시오
아래 코드 (C #)는 대상 요소가 표시되도록합니다.
internal static bool ElementIsDisplayed()
{
IWebDriver driver = new ChromeDriver();
driver.Url = "http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp";
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
By locator = By.CssSelector("input[value='csharp']:first-child");
IWebElement myDynamicElement = wait.Until<IWebElement>((d) =>
{
return d.FindElement(locator);
});
return myDynamicElement.Displayed;
}
페이지가 jQuery를 지원하는 경우 jQuery.active 함수 를 사용하여 모든 ajax 호출이 완료된 후 대상 요소가 검색되도록 할 수 있습니다 .
public static bool ElementIsDisplayed()
{
IWebDriver driver = new ChromeDriver();
driver.Url = "http://www.seleniumhq.org/docs/04_webdriver_advanced.jsp";
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));
By locator = By.CssSelector("input[value='csharp']:first-child");
return wait.Until(d => ElementIsDisplayed(d, locator));
}
public static bool ElementIsDisplayed(IWebDriver driver, By by)
{
try
{
if (driver.FindElement(by).Displayed)
{
//jQuery is supported.
if ((bool)((IJavaScriptExecutor)driver).ExecuteScript("return window.$ != undefined"))
{
return (bool)((IJavaScriptExecutor)driver).ExecuteScript("return $.active == 0");
}
else
{
return true;
}
}
else
{
return false;
}
}
catch (Exception)
{
return false;
}
}
Morten Christiansen의 답변을 기반으로 한 멋진 버전이 있습니다.
void waitForAjaxCallsToComplete() {
repeatUntil(
{ return getJavaScriptFunction(driver, "return (window.jQuery || {active : false}).active") },
"Ajax calls did not complete before timeout."
)
}
static void repeatUntil(Closure runUntilTrue, String errorMessage, int pollFrequencyMS = 250, int timeOutSeconds = 10) {
def today = new Date()
def end = today.time + timeOutSeconds
def complete = false;
while (today.time < end) {
if (runUntilTrue()) {
complete = true;
break;
}
sleep(pollFrequencyMS);
}
if (!complete)
throw new TimeoutException(errorMessage);
}
static String getJavaScriptFunction(WebDriver driver, String jsFunction) {
def jsDriver = driver as JavascriptExecutor
jsDriver.executeScript(jsFunction)
}
위에서 언급했듯이 활성 연결이 닫힐 때까지 기다릴 수 있습니다.
private static void WaitForReady() {
WebDriverWait wait = new WebDriverWait(webDriver, waitForElement);
wait.Until(driver => (bool)((IJavaScriptExecutor)driver).ExecuteScript("return jQuery.active == 0"));
}
My observation is this is not reliable as data transfer happens very quickly. Much more time is consumed on data processing and rendering on the page and even jQuery.active == 0
data might not be yet on the page.
Much wiser is to use an explicit wait for element to be shown on the page, see some of the answers related to this.
The best situation is if your web application have some custom loader or indication that data is being processed. In this case you can just wait for this indication to hide.
This works like a charm for me :
public void waitForAjax() {
try {
WebDriverWait driverWait = new WebDriverWait(driver, 10);
ExpectedCondition<Boolean> expectation;
expectation = new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver driverjs) {
JavascriptExecutor js = (JavascriptExecutor) driverjs;
return js.executeScript("return((window.jQuery != null) && (jQuery.active === 0))").equals("true");
}
};
driverWait.until(expectation);
}
catch (TimeoutException exTimeout) {
// fail code
}
catch (WebDriverException exWebDriverException) {
// fail code
}
return this;
}
If the control you are waiting for is an "Ajax" web element, the following code will wait for it, or any other Ajax web element to finish loading or performing whatever it needs to do so that you can more-safely continue with your steps.
public static void waitForAjaxToFinish() {
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver wdriver) {
return ((JavascriptExecutor) driver).executeScript(
"return jQuery.active == 0").equals(true);
}
});
}
Below is my code for fetch. Took me while researching because jQuery.active doesn't work with fetch. Here is the answer helped me proxy fetch, but its only for ajax not fetch mock for selenium
public static void customPatchXMLHttpRequest(WebDriver driver) {
try {
if (driver instanceof JavascriptExecutor) {
JavascriptExecutor jsDriver = (JavascriptExecutor) driver;
Object numberOfAjaxConnections = jsDriver.executeScript("return window.openHTTPs");
if (numberOfAjaxConnections instanceof Long) {
return;
}
String script = " (function() {" + "var oldFetch = fetch;"
+ "window.openHTTPs = 0; console.log('starting xhttps');" + "fetch = function(input,init ){ "
+ "window.openHTTPs++; "
+ "return oldFetch(input,init).then( function (response) {"
+ " if (response.status >= 200 && response.status < 300) {"
+ " window.openHTTPs--; console.log('Call completed. Remaining active calls: '+ window.openHTTPs); return response;"
+ " } else {"
+ " window.openHTTPs--; console.log('Call fails. Remaining active calls: ' + window.openHTTPs); return response;"
+ " };})" + "};" + "var oldOpen = XMLHttpRequest.prototype.open;"
+ "XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {"
+ "window.openHTTPs++; console.log('xml ajax called');"
+ "this.addEventListener('readystatechange', function() {" + "if(this.readyState == 4) {"
+ "window.openHTTPs--; console.log('xml ajax complete');" + "}" + "}, false);"
+ "oldOpen.call(this, method, url, async, user, pass);" + "}" +
"})();";
jsDriver.executeScript(script);
} else {
System.out.println("Web driver: " + driver + " cannot execute javascript");
}
} catch (Exception e) {
System.out.println(e);
}
}
For those who is using primefaces, just do:
selenium.waitForCondition("selenium.browserbot.getCurrentWindow().$.active==0", defaultWaitingPeriod);
참고URL : https://stackoverflow.com/questions/2835179/how-to-get-selenium-to-wait-for-ajax-response
'development' 카테고리의 다른 글
bash 스크립트 내에서 ssh하는 방법은 무엇입니까? (0) | 2020.12.12 |
---|---|
로그 백 구성 파일에서 환경 변수 읽기 (0) | 2020.12.12 |
MySQL의 대소 문자 구분 데이터 정렬 (0) | 2020.12.12 |
문자열 일치 후 단어를 가져 오는 정규식 (0) | 2020.12.12 |
파일 또는 폴더를 놓기 전에 끌고 있는지 구별하는 방법은 무엇입니까? (0) | 2020.12.12 |