브라우저에서, 바람직하게는 셀레늄을 사용하여 extjs 코드를 테스트하기 위한 제안 사항이 있습니까?

StackOverflow https://stackoverflow.com/questions/107314

문제

우리는 (모듈 수준의 광범위한 Python Doctest 외에도) 높은 수준의 웹 사이트 테스트를 처리하기 위해 Selenium을 성공적으로 사용해 왔습니다.그러나 이제 우리는 많은 페이지에 extjs를 사용하고 있으며 그리드와 같은 복잡한 구성 요소에 대한 Selenium 테스트를 통합하기가 어렵다는 것이 입증되었습니다.

extjs 기반 웹 페이지에 대한 자동 테스트를 성공적으로 작성해 본 사람이 있나요?인터넷 검색을 많이 하면 비슷한 문제를 가진 사람들을 찾을 수 있지만 답변은 거의 없습니다.감사해요!

도움이 되었습니까?

해결책

Selenium으로 ExtJS를 테스트할 때 가장 큰 장애물은 ExtJS가 표준 HTML 요소를 렌더링하지 않으며 Selenium IDE가 장식 역할만 하는 요소(전체 데스크탑에서 ExtJS를 돕는 불필요한 요소)를 대상으로 하는 명령을 순진하게(그리고 정당하게) 생성한다는 것입니다. 보고 느끼다.다음은 ExtJS 앱에 대한 자동화된 Selenium 테스트를 작성하는 동안 수집한 몇 가지 팁과 요령입니다.

일반 팁

요소 찾기

Firefox에서 Selenium IDE를 사용하여 사용자 작업을 기록하여 Selenium 테스트 사례를 생성할 때 Selenium은 HTML 요소의 ID를 기반으로 기록된 작업을 기반으로 합니다.그러나 대부분의 클릭 가능한 요소에 대해 ExtJS는 코드가 변경되지 않았더라도 동일한 페이지를 나중에 방문할 때 변경될 가능성이 있는 "ext-gen-345"와 같은 생성된 ID를 사용합니다.테스트를 위해 사용자 작업을 기록한 후에는 생성된 ID에 의존하는 모든 작업을 수행하고 교체하는 수동 작업이 필요합니다.교체에는 두 가지 유형이 있습니다.

ID 로케이터를 CSS 또는 XPath 로케이터로 바꾸기

CSS 로케이터는 "css="로 시작하고 XPath 로케이터는 "//"로 시작합니다("xpath=" 접두사는 선택 사항입니다).CSS 로케이터는 덜 장황하고 읽기 쉬우며 XPath 로케이터보다 선호됩니다.그러나 CSS 로케이터로는 간단히 잘라낼 수 없기 때문에 XPath 로케이터를 사용해야 하는 경우가 있습니다.

자바스크립트 실행

일부 요소에는 ExtJS가 수행하는 복잡한 렌더링으로 인해 단순한 마우스/키보드 상호 작용 이상이 필요합니다.예를 들어 Ext.form.CombBox는 실제로는 <select> 요소는 문서 트리 하단 어딘가에 있는 분리된 드롭다운 목록이 있는 텍스트 입력입니다.ComboBox 선택을 적절하게 시뮬레이션하려면 먼저 드롭다운 화살표 클릭을 시뮬레이션한 다음 나타나는 목록을 클릭하는 것이 가능합니다.그러나 CSS 또는 XPath 로케이터를 통해 이러한 요소를 찾는 것은 번거로울 수 있습니다.대안은 ComoBox 구성 요소 자체를 찾고 해당 구성 요소에 대한 메서드를 호출하여 선택을 시뮬레이션하는 것입니다.

var combo = Ext.getCmp('genderComboBox'); // returns the ComboBox components
combo.setValue('female'); // set the value
combo.fireEvent('select'); // because setValue() doesn't trigger the event

셀레늄에서는 runScript 명령을 사용하면 위 작업을 보다 간결한 형식으로 수행할 수 있습니다.

with (Ext.getCmp('genderComboBox')) { setValue('female'); fireEvent('select'); }

AJAX 및 느린 렌더링에 대처하기

Selenium에는 사용자 작업으로 인해 페이지가 전환되거나 다시 로드될 때 페이지 로드를 기다리는 모든 명령에 대해 "*AndWait" 특성이 있습니다.그러나 AJAX 가져오기에는 실제 페이지 로드가 포함되지 않으므로 이러한 명령을 동기화에 사용할 수 없습니다.해결책은 AJAX 진행률 표시기의 존재 여부나 그리드의 행 모양, 추가 구성 요소, 링크 등과 같은 시각적 단서를 활용하는 것입니다.예를 들어:

Command: waitForElementNotPresent
Target: css=div:contains('Loading...')

사용자 작업으로 인해 보기가 변경된 후 ExtJS가 구성 요소를 렌더링하는 속도에 따라 요소가 특정 시간 후에만 나타나는 경우도 있습니다.임의의 지연을 사용하는 대신 pause 명령을 내릴 때 이상적인 방법은 관심 있는 요소가 우리 손에 들어올 때까지 기다리는 것입니다.예를 들어 항목이 나타날 때까지 기다린 후 항목을 클릭하려면 다음을 수행하세요.

Command: waitForElementPresent
Target: css=span:contains('Do the funky thing')
Command: click
Target: css=span:contains('Do the funky thing')

다른 브라우저나 다른 컴퓨터에서 테스트를 실행하면 타이밍 차이로 인해 테스트 케이스가 불안정해지기 때문에 임의의 일시 중지에 의존하는 것은 좋은 생각이 아닙니다.

클릭할 수 없는 항목

일부 요소는 다음에 의해 실행될 수 없습니다. click 명령.이벤트 리스너가 실제로 컨테이너에 있고 하위 요소에서 마우스 이벤트를 감시하여 결국 상위 요소로 버블링되기 때문입니다.탭 컨트롤이 한 예입니다.탭을 클릭하려면 다음을 시뮬레이션해야 합니다. mouseDown 탭 레이블의 이벤트:

Command: mouseDownAt
Target: css=.x-tab-strip-text:contains('Options')
Value: 0,0

현장 검증

검증을 위한 정규식 또는 vtype과 관련된 양식 필드(Ext.form.* 구성 요소)는 특정 지연을 통해 검증을 트리거합니다(참조: validationDelay 속성은 기본적으로 250ms로 설정됨), 사용자가 텍스트를 입력한 후 또는 필드가 초점을 잃거나 흐려지는 즉시(참조: validateOnDelay 재산).필드 내부에 일부 텍스트를 입력하기 위해 type Selenium 명령을 실행한 후 필드 유효성 검사를 트리거하려면 다음 중 하나를 수행해야 합니다.

  • 지연된 검증 트리거

    ExtJS는 필드가 키업 이벤트를 수신하면 유효성 검사 지연 타이머를 시작합니다.이 타이머를 트리거하려면 간단히 더미 keyup 이벤트를 발행하고(ExtJS는 이를 무시하므로 어떤 키를 사용하는지는 중요하지 않음) ValidationDelay보다 긴 짧은 일시 중지가 뒤따릅니다.

    Command: keyUp
    Target: someTextArea
    Value: x
    Command: pause
    Target: 500
    
  • 즉시 검증 트리거

    필드에 흐림 이벤트를 삽입하여 즉각적인 유효성 검사를 트리거할 수 있습니다.

    Command: runScript
    Target: someComponent.nameTextField.fireEvent("blur")
    

검증 결과 확인

검증 후에는 오류 필드의 존재 여부를 확인할 수 있습니다.

Command: verifyElementNotPresent   
Target: //*[@id="nameTextField"]/../*[@class="x-form-invalid-msg" and not(contains(@style, "display: none"))]

Command: verifyElementPresent   
Target: //*[@id="nameTextField"]/../*[@class="x-form-invalid-msg" and not(contains(@style, "display: none"))]

"디스플레이:없음" 검사가 필요한 이유는 오류 필드가 표시되면 숨겨야 하기 때문입니다. ExtJS는 오류 필드를 DOM 트리에서 완전히 제거하는 대신 단순히 숨깁니다.

요소별 팁

Ext.form.Button 클릭

  • 옵션 1

    명령:대상을 클릭하십시오 :css=버튼:포함('저장')

    캡션으로 버튼을 선택합니다.

  • 옵션 2

    명령:대상을 클릭하십시오 :css=#저장 옵션 버튼

    ID로 버튼을 선택합니다.

Ext.form.ComboBox에서 값 선택

Command: runScript
Target: with (Ext.getCmp('genderComboBox')) { setValue('female'); fireEvent('select'); }

먼저 값을 설정한 다음 관찰자가 있는 경우 선택 이벤트를 명시적으로 시작합니다.

다른 팁

이것 블로그 나에게 많은 도움이되었습니다.그는 이 주제에 관해 꽤 많은 글을 썼고, 그 주제는 여전히 활발히 활동 중인 것 같습니다.그 사람도 좋은 디자인을 높이 평가하는 것 같아요.

그는 기본적으로 자바스크립트 전송을 사용하여 쿼리를 수행하고 Ext.ComponentQuery.query 메소드를 사용하여 내부 앱에서와 동일한 방식으로 항목을 검색하는 방법에 대해 설명합니다.그렇게 하면 xtypes와 itemId를 사용할 수 있고 미친 자동 생성 항목을 구문 분석하는 것에 대해 걱정할 필요가 없습니다.

나는 찾았다 이 기사 특히 매우 도움이 됩니다.

곧 여기에 좀 더 자세한 내용을 게시할 수도 있습니다. 아직 이 작업을 올바르게 수행하는 방법에 대해 알아보고 있습니다.

저는 Selenium을 사용하여 ExtJs 웹 애플리케이션을 테스트해 왔습니다.가장 큰 문제 중 하나는 무언가를 하기 위해 그리드에서 항목을 선택하는 것이었습니다.

이를 위해 나는 도우미 메소드를 작성했습니다(ExtJ와 더 쉽게 상호 작용할 수 있는 유용한 메소드 모음인 SeleniumExtJsUtils 클래스에 있음).

/**
 * Javascript needed to execute in order to select row in the grid
 * 
 * @param gridId Grid id
 * @param rowIndex Index of the row to select
 * @return Javascript to select row
 */
public static String selectGridRow(String gridId, int rowIndex) {
    return "Ext.getCmp('" + gridId + "').getSelectionModel().selectRow(" + rowIndex + ", true)";
}

행을 선택해야 할 때 다음을 호출하면 됩니다.

selenium.runScript( SeleniumExtJsUtils.selectGridRow("<myGridId>", 5) );

이것이 작동하려면 그리드에 내 ID를 설정하고 ExtJ가 자신의 ID를 생성하지 못하게 해야 합니다.

해당 요소가 표시되는지 감지하려면 다음 절을 사용합니다.not(contains(@style, "display: none")

이것을 사용하는 것이 더 좋습니다:

visible_clause = "not(ancestor::*[contains(@style,'display: none')" +
    " or contains(@style, 'visibility: hidden') " + 
    " or contains(@class,'x-hide-display')])"

hidden_clause = "parent::*[contains(@style,'display: none')" + 
    " or contains(@style, 'visibility: hidden')" + 
    " or contains(@class,'x-hide-display')]"

extjs 테스트와 관련하여 겪고 있는 문제 유형에 대해 더 많은 통찰력을 제공할 수 있습니까?

내가 유용하다고 생각하는 Selenium 확장 중 하나는 다음과 같습니다. 대기조건.Ajax 이벤트에 문제가 있는 것 같으면 waitForCondition을 사용하여 이벤트가 발생할 때까지 기다릴 수 있습니다.

Ext JS 웹 페이지는 Ext JS 그리드처럼 생성되는 복잡한 HTML로 인해 테스트하기 까다로울 수 있습니다.

HTML5 로봇 동적이지 않은 속성과 조건을 기반으로 구성 요소를 안정적으로 검색하고 상호 작용하는 방법에 대한 일련의 모범 사례를 사용하여 이 문제를 처리합니다.그런 다음 상호 작용해야 하는 모든 HTML, Ext JS 및 Sencha Touch 구성 요소에 대해 이 작업을 수행하기 위한 바로 가기를 제공합니다.2가지 맛이 있습니다:

  1. 자바 - 모든 최신 브라우저에 대한 웹 드라이버 지원이 내장된 친숙한 Selenium 및 JUnit 기반 API입니다.
  2. 그웬 - 자체 통합 개발 환경과 함께 제공되는 브라우저 테스트를 빠르고 쉽게 생성하고 유지 관리할 수 있는 휴먼 스타일 언어입니다.모두 Java API를 기반으로 합니다.

예를 들어 "Foo"라는 텍스트가 포함된 Ext JS 그리드 행을 찾으려면 Java에서 다음을 수행할 수 있습니다.

findExtJsGridRow("Foo");

...Gwen에서는 다음을 수행할 수 있습니다.

extjsgridrow by text "Foo"

둘 다에 대한 많은 문서가 있습니다 자바 Ext JS 특정 구성 요소를 사용하여 작업하는 방법에 대한 Gwen.또한 문서에는 이러한 모든 Ext JS 구성 요소에 대한 결과 HTML이 자세히 설명되어 있어 유용할 수도 있습니다.

페이지의 그리드 ID를 통해 그리드를 가져오는 데 유용한 팁:이 API를 통해 더욱 유용한 기능을 확장할 수 있다고 생각합니다.

   sub get_grid_row {
        my ($browser, $grid, $row)  = @_;


        my $script = "var doc = this.browserbot.getCurrentWindow().document;\n" .
            "var grid = doc.getElementById('$grid');\n" .
            "var table = grid.getElementsByTagName('table');\n" .
            "var result = '';\n" .
            "var row = 0;\n" . 
            "for (var i = 0; i < table.length; i++) {\n" .
            "   if (table[i].className == 'x-grid3-row-table') {\n".
            "       row++;\n" . 
            "       if (row == $row) {\n" .
            "           var cols_len = table[i].rows[0].cells.length;\n" .
            "           for (var j = 0; j < cols_len; j++) {\n" .
            "               var cell = table[i].rows[0].cells[j];\n" .
            "               if (result.length == 0) {\n" .
            "                   result = getText(cell);\n" .
            "               } else { \n" .
            "                   result += '|' + getText(cell);\n" .
            "               }\n" .
            "           }\n" .
            "       }\n" .
            "   }\n" .
            "}\n" .
            "result;\n";

        my $result = $browser->get_eval($script);
        my @res = split('\|', $result);
        return @res;
    }

사용자 정의 HTML 데이터 속성을 통한 보다 쉬운 테스트

로부터 센차 문서:

itemId는 개체 참조를 사용할 수 없을 때 구성 요소에 대한 참조를 가져오는 대체 방법으로 사용할 수 있습니다.Ext.getCmp에서 ID를 사용하는 대신 itemId 또는 id를 검색하는 Ext.container.Container.getComponent에서 itemId를 사용하세요.itemId는 컨테이너의 내부 MixedCollection에 대한 인덱스이므로 itemId의 범위는 컨테이너에 대해 로컬로 지정됩니다. 따라서 고유 ID가 필요한 Ext.ComponentManager와의 잠재적인 충돌을 방지할 수 있습니다.

재정의 Ext.AbstractComponent'에스 onBoxReady 메서드를 사용하여 사용자 정의 데이터 속성을 설정했습니다(이름은 내 사용자 정의에서 따옴). testIdAttr 각 구성요소의 속성)을 구성요소의 itemId 값(존재하는 경우)추가 Testing.overrides.AbstractComponent 당신의 수업 application.js 파일의 requires 정렬.

/**
 * Overrides the Ext.AbstracComponent's onBoxReady
 * method to add custom data attributes to the
 * component's dom structure.
 *
 * @author Brian Wendt
 */
Ext.define('Testing.overrides.AbstractComponent', {
  override: 'Ext.AbstractComponent',


  onBoxReady: function () {
    var me = this,
      el = me.getEl();


    if (el && el.dom && me.itemId) {
      el.dom.setAttribute(me.testIdAttr || 'data-selenium-id', me.itemId);
    }


    me.callOverridden(arguments);
  }
});

이 방법은 개발자에게 코드 내에서 설명 식별자를 재사용하고 페이지가 렌더링될 때마다 해당 식별자를 사용할 수 있도록 하는 방법을 제공합니다.더 이상 설명이 없고 동적으로 생성된 ID를 검색할 필요가 없습니다.

우리는 Selenium을 사용하는 테스트 프레임워크를 개발 중이며 extjs에 문제가 발생했습니다(클라이언트 측 렌더링이기 때문에).DOM이 준비되면 요소를 찾는 것이 유용하다고 생각합니다.

public static boolean waitUntilDOMIsReady(WebDriver driver) {
    def maxSeconds = DEFAULT_WAIT_SECONDS * 10
    for (count in 1..maxSeconds) {
        Thread.sleep(100)
        def ready = isDOMReady(driver);
        if (ready) {
            break;
        }
    }
}

public static boolean isDOMReady(WebDriver driver){
    return driver.executeScript("return document.readyState");
}

형식적인 HTML이 아닌 복잡한 UI의 경우 xPath는 항상 믿을 수 있는 것이지만 ExtJ를 사용하는 다양한 UI 구현의 경우 약간 복잡합니다.

Firebug 및 Firexpath를 firefox 확장으로 사용하여 특정 요소의 xpath를 테스트하고 전체 xpath를 셀레늄에 대한 매개변수로 간단히 전달할 수 있습니다.

예를 들어 Java 코드에서는 다음과 같습니다.

String fullXpath = "xpath=//div[@id='mainDiv']//div[contains(@class,'x-grid-row')]//table/tbody/tr[1]/td[1]//button"

selenium.click(fullXpath);

WebDriver를 사용하여 ExtJS 애플리케이션을 테스트할 때 다음 접근 방식을 사용했습니다.라벨의 텍스트로 필드를 찾아서 얻었습니다. @for 라벨의 속성.예를 들어 라벨이 있습니다.

<label id="dynamic_id_label" class="TextboxLabel" for="textField_which_I_am_lloking_for">
Name Of Needed Label
<label/>

그리고 WebDriver에 몇 가지 입력을 지정해야 합니다. //input[@id=(//label[contains(text(),'Name Of Needed Label')]/@for)].

따라서 ID는 다음에서 선택됩니다. @for 속성을 지정하고 추가로 사용하세요.이는 아마도 가장 간단한 경우이지만 요소를 찾는 방법을 제공합니다.레이블이 없으면 훨씬 더 어렵지만 일부 요소를 찾고 형제, 하강/상승 요소를 찾는 xpath를 작성해야 합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top