각도 테스트셀레늄이 있는 JS
스택 ASP MVC + Angular에 SPA 어플리케이션이 있다.JS와 저는 UI를 테스트하고 싶습니다.지금은 셀레늄과 팬텀을 시도하고 있어JS 및 WebKit 드라이버.
단일 요소가 포함된 샘플 테스트 페이지 보기입니다. 항목 " " "<li>
앵귤러
<div id="items">
<li>text</li>
<li>text2</li>
</div>
테스트를 통과하려고 하는데 다음 행에 오류가 있습니다.
_driver.FindElements(By.TagName('li'))
이 시점에서는 로드된 요소와 _driver는 없습니다.PageSource에 요소가 없습니다.
어떻게 하면 아이템이 로딩될 때까지 기다릴 수 있나요?★★★★★★★★★★★★★★★★는 추천하지 말아 주세요.Thread.Sleep()
페이지 로드 / jquery.ajax(존재하는 경우) 및 $http 호출 및 그에 따른 다이제스트/렌더 사이클을 대기하고 유틸리티 함수로 던져놓고 대기합니다.
/* C# Example
var pageLoadWait = new WebDriverWait(WebDriver, TimeSpan.FromSeconds(timeout));
pageLoadWait.Until<bool>(
(driver) =>
{
return (bool)JS.ExecuteScript(
@"*/
try {
if (document.readyState !== 'complete') {
return false; // Page not loaded yet
}
if (window.jQuery) {
if (window.jQuery.active) {
return false;
} else if (window.jQuery.ajax && window.jQuery.ajax.active) {
return false;
}
}
if (window.angular) {
if (!window.qa) {
// Used to track the render cycle finish after loading is complete
window.qa = {
doneRendering: false
};
}
// Get the angular injector for this app (change element if necessary)
var injector = window.angular.element('body').injector();
// Store providers to use for these checks
var $rootScope = injector.get('$rootScope');
var $http = injector.get('$http');
var $timeout = injector.get('$timeout');
// Check if digest
if ($rootScope.$$phase === '$apply' || $rootScope.$$phase === '$digest' || $http.pendingRequests.length !== 0) {
window.qa.doneRendering = false;
return false; // Angular digesting or loading data
}
if (!window.qa.doneRendering) {
// Set timeout to mark angular rendering as finished
$timeout(function() {
window.qa.doneRendering = true;
}, 0);
return false;
}
}
return true;
} catch (ex) {
return false;
}
/*");
});*/
웹 사이트가 Angular를 사용하는지 여부를 확인할 수 있는 새 클래스를 만듭니다.JS는 다음과 같이 AJAX 콜의 송신을 종료했습니다.
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;
public class AdditionalConditions {
public static ExpectedCondition<Boolean> angularHasFinishedProcessing() {
return new ExpectedCondition<Boolean>() {
@Override
public Boolean apply(WebDriver driver) {
return Boolean.valueOf(((JavascriptExecutor) driver).executeScript("return (window.angular !== undefined) && (angular.element(document).injector() !== undefined) && (angular.element(document).injector().get('$http').pendingRequests.length === 0)").toString());
}
};
}
}
다음 코드를 사용하여 코드의 모든 위치에서 사용할 수 있습니다.
WebDriverWait wait = new WebDriverWait(getDriver(), 15, 100);
wait.until(AdditionalConditions.angularHasFinishedProcessing()));
사내 프레임워크가 여러 사이트를 테스트하기 위해 사용되고 있고, 일부는 JQuery를 사용하고 있으며, 일부는 AngularJs를 사용하고 있습니다(또한 1은 혼합되어 있습니다!).프레임워크는 C#로 작성되어 있기 때문에 실행 중인 JScript는 (디버깅을 위해) 최소한의 청크로 실행하는 것이 중요합니다.실제로 위의 답변 중 많은 것을 취해서 그것들을 함께 뭉쳤다(따라서 신용이 있어야 할 곳은 @npjohns).다음은 우리가 수행한 작업에 대한 설명입니다.
다음은 HTML DOM이 로드된 경우 true/false를 반환합니다.
public bool DomHasLoaded(IJavaScriptExecutor jsExecutor, int timeout = 5)
{
var hasThePageLoaded = jsExecutor.ExecuteScript("return document.readyState");
while (hasThePageLoaded == null || ((string)hasThePageLoaded != "complete" && timeout > 0))
{
Thread.Sleep(100);
timeout--;
hasThePageLoaded = jsExecutor.ExecuteScript("return document.readyState");
if (timeout != 0) continue;
Console.WriteLine("The page has not loaded successfully in the time provided.");
return false;
}
return true;
}
다음으로 JQuery가 사용되고 있는지 여부를 확인합니다.
public bool IsJqueryBeingUsed(IJavaScriptExecutor jsExecutor)
{
var isTheSiteUsingJQuery = jsExecutor.ExecuteScript("return window.jQuery != undefined");
return (bool)isTheSiteUsingJQuery;
}
JQuery가 사용되는 경우 로드되었는지 확인합니다.
public bool JqueryHasLoaded(IJavaScriptExecutor jsExecutor, int timeout = 5)
{
var hasTheJQueryLoaded = jsExecutor.ExecuteScript("jQuery.active === 0");
while (hasTheJQueryLoaded == null || (!(bool) hasTheJQueryLoaded && timeout > 0))
{
Thread.Sleep(100);
timeout--;
hasTheJQueryLoaded = jsExecutor.ExecuteScript("jQuery.active === 0");
if (timeout != 0) continue;
Console.WriteLine(
"JQuery is being used by the site but has failed to successfully load.");
return false;
}
return (bool) hasTheJQueryLoaded;
}
그런 다음 Angular에 대해 동일한 작업을 수행합니다.JS:
public bool AngularIsBeingUsed(IJavaScriptExecutor jsExecutor)
{
string UsingAngular = @"if (window.angular){
return true;
}";
var isTheSiteUsingAngular = jsExecutor.ExecuteScript(UsingAngular);
return (bool) isTheSiteUsingAngular;
}
사용 중인 경우 로드되었는지 확인합니다.
public bool AngularHasLoaded(IJavaScriptExecutor jsExecutor, int timeout = 5)
{
string HasAngularLoaded =
@"return (window.angular !== undefined) && (angular.element(document.body).injector() !== undefined) && (angular.element(document.body).injector().get('$http').pendingRequests.length === 0)";
var hasTheAngularLoaded = jsExecutor.ExecuteScript(HasAngularLoaded);
while (hasTheAngularLoaded == null || (!(bool)hasTheAngularLoaded && timeout > 0))
{
Thread.Sleep(100);
timeout--;
hasTheAngularLoaded = jsExecutor.ExecuteScript(HasAngularLoaded);
if (timeout != 0) continue;
Console.WriteLine(
"Angular is being used by the site but has failed to successfully load.");
return false;
}
return (bool)hasTheAngularLoaded;
}
DOM 이 정상적으로 로드되고 있는 것을 확인하면, 다음의 bool 값을 사용해 커스텀 대기를 실행할 수 있습니다.
var jquery = !IsJqueryBeingUsed(javascript) || wait.Until(x => JQueryHasLoaded(javascript));
var angular = !AngularIsBeingUsed(javascript) || wait.Until(x => AngularHasLoaded(javascript));
Angular를 사용하는 경우그렇다면 JS는 Protractor를 사용하는 것이 좋습니다.
프록터를 사용하는 경우 http 요구가 완료될 때까지 대기하는 wait For Angular() 메서드를 사용할 수 있습니다.요소가 표시될 때까지 기다렸다가 실행하는 것이 좋습니다.언어 및 구현에 따라서는 동기 언어로 표시될 수 있습니다.
WebDriverWait wait = new WebDriverWait(webDriver, timeoutInSeconds);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.id<locator>));
또는 JS에서는 true를 반환할 때까지 함수를 실행하는 wait 메서드를 사용할 수 있습니다.
browser.wait(function () {
return browser.driver.isElementPresent(elementToFind);
});
유용한 코드 조각들을 얻기 위해 굴착기를 채굴해도 좋습니다.이 함수는 Angular가 페이지 렌더링을 완료할 때까지 차단합니다.Shahzaib Salim의 답변의 변형입니다.단, Shahzaib Salim은 폴링하고 있고, 저는 콜백을 설정하고 있습니다.
def wait_for_angular(self, selenium):
self.selenium.set_script_timeout(10)
self.selenium.execute_async_script("""
callback = arguments[arguments.length - 1];
angular.element('html').injector().get('$browser').notifyWhenNoOutstandingRequests(callback);""")
'html은 ''이라는 ng-app
.
https://github.com/angular/protractor/blob/71532f055c720b533fbf9dab2b3100b657966da6/lib/clientsidescripts.js#L51 에서 입수할 수 있습니다.
다음 코드를 실행했는데 비동기 레이스 조건 실패에 도움이 되었습니다.
$window._docReady = function () {
var phase = $scope.$root.$$phase;
return $http.pendingRequests.length === 0 && phase !== '$apply' && phase !== '$digest';
}
Selenium PageObject 모델에서는 다음을 기다릴 수 있습니다.
Object result = ((RemoteWebDriver) driver).executeScript("return _docReady();");
return result == null ? false : (Boolean) result;
말씀하신 대로 웹 앱이 실제로 Angular를 사용하여 작성되었다면 엔드 투 엔드 테스트를 수행하는 가장 좋은 방법은 Protractor를 사용하는 것입니다.
프로젝터는 프로젝터, 프로젝터 waitForAngular
방법 - 각도 수정이 완료될 때까지 자동으로 대기합니다.
따라서, 일반적인 경우, 당신은 명시적인 것을 쓸 필요가 없습니다.wait
테스트 케이스의 경우: 연장기가 대신합니다.
Angular Phonecat 튜토리얼을 참조하여 프로젝터를 설정하는 방법을 배울 수 있습니다.
프로젝터를 진지하게 사용하려면 페이지 오브젝트를 채택해야 합니다.예를 들어 Angular Phonecat의 my page object 테스트 스위트를 참조하십시오.
Protractor를 사용하면 테스트를 C#이 아닌 Javascript(Protractor는 실제로 노드를 기반으로 함)로 작성할 수 있지만, 그 대가로 Protractor는 모든 것을 기다립니다.
iframes를 포함하고 Englular와 함께 개발된 HTML 페이지에 대한 나의 특별한 문제는JS는 다음 트릭을 통해 많은 시간을 절약할 수 있었습니다.DOM에는 모든 내용을 감싸는 iframe이 있는 것을 분명히 보았습니다.다음 코드가 작동해야 합니다.
driver.switchTo().frame(0);
waitUntilVisibleByXPath("//h2[contains(text(), 'Creative chooser')]");
하지만 그것은 작동하지 않았고 "프레임으로 전환할 수 없습니다.창이 닫혔습니다.그 후 코드를 다음과 같이 수정했습니다.
driver.switchTo().defaultContent();
driver.switchTo().frame(0);
waitUntilVisibleByXPath("//h2[contains(text(), 'Creative chooser')]");
그 후 모든 것이 순조롭게 진행되었다.따라서 Angular는 iframes로 무언가를 망치고 있었고, 그 드라이버는 기본 콘텐츠에 초점을 맞추고 있다고 예상했을 때 Angular 프레임에 의해 이미 삭제된 일부에 의해 초점이 맞춰졌습니다.이게 여러분들에게 도움이 되길 바랍니다.
만약 당신이 모든 것을 Protractor로 바꾸고 싶지 않지만 Angular를 기다리고 싶다면, 나는 Paul Hammants ngWebDriver(Java)를 사용하는 것을 추천합니다.그것은 견인기를 기반으로 하지만 당신은 바꿀 필요가 없습니다.
액션을 실행하기 전에 Angular(ngWebDriver의 waitForAngularRequestsToFinish()를 사용하여)를 기다리는 액션 클래스를 작성하여 문제를 해결했습니다.
코드 스니펫에 대해서는 이 질문에 대한 답변을 참조하십시오.
다음은 WebDriverJS를 사용하는 경우 Angular에서 대기하는 방법의 예입니다.원래는 커스텀 조건을 만들어야 한다고 생각했는데wait
는 임의의 기능을 받아들입니다.
// Wait for Angular to Finish
function angularReady(): any {
return $browser.executeScript("return (window.angular !== undefined) && (angular.element(document).injector() !== undefined) && (angular.element(document).injector().get('$http').pendingRequests.length === 0)")
.then(function(angularIsReady) {
return angularIsReady === true;
});
}
$browser.wait(angularReady, 5000).then(...);
안타깝게도 이것은 팬텀과 함께 작동하지 않습니다.CSP(content-security-policy)에 의한 JS 및unsafe-eval
. Windows에서 헤드리스 Chrome 59를 기다릴 수 없습니다.
D Sayar의 답변을 바탕으로 사용법을 구현했습니다. 그리고 누군가에게 도움이 될 수 있습니다.여기서 언급한 모든 부울 함수를 단일 클래스에 복사하고 PageCallingUtility() 메서드 아래에 추가해야 합니다.이 메서드는 내부 종속성을 호출합니다.
통상의 사용법에서는, PageCallingUtility() 메서드를 직접 호출할 필요가 있습니다.
public void PageCallingUtility()
{
if (DomHasLoaded() == true)
{
if (IsJqueryBeingUsed() == true)
{
JqueryHasLoaded();
}
if (AngularIsBeingUsed() == true)
{
AngularHasLoaded();
}
}
}
에디크의 제안 말고.각을 테스트하는 경우JS 앱, 나는 당신이 프로젝터에 대해 생각해 볼 것을 강력히 권합니다.
프로젝터가 대기 문제(동기, 비동기)를 해결하는 데 도움이 됩니다.하지만 몇 가지 주의사항이 있습니다.
1 - javascript에서 테스트를 개발해야 합니다.
2 - 흐름 처리에는 몇 가지 다른 메커니즘이 있습니다.
언급URL : https://stackoverflow.com/questions/25062969/testing-angularjs-with-selenium
'programing' 카테고리의 다른 글
Postgres의 JSON 필드에 인덱스를 작성하는 방법 (0) | 2023.03.02 |
---|---|
URI [/WEB-INF/pages/apiForm.jsp]를 사용한 HTTP 요청에 대한 매핑을 찾을 수 없습니다. (0) | 2023.03.02 |
WordPress + 멀티사이트:Network Admin에서 Add New Site 양식에 커스텀 블로그 옵션을 추가하는 방법 (0) | 2023.03.02 |
Django REST Framework 업로드 이미지: "제출된 데이터가 파일이 아닙니다." (0) | 2023.03.02 |
html을 반응으로 안전하게 렌더링하는 방법 (0) | 2023.03.02 |