브라우저에서, 가급적 셀레늄을 사용하여 extjs 코드를 테스트하기위한 제안이 있습니까?


92

우리는 높은 수준의 웹 사이트 테스트를 처리하기 위해 셀레늄을 성공적으로 사용하고 있습니다 (모듈 수준의 광범위한 파이썬 문서 테스트에 추가로). 그러나 이제 우리는 많은 페이지에 extjs를 사용하고 있으며 그리드와 같은 복잡한 구성 요소에 대해 Selenium 테스트를 통합하기가 어렵습니다.

extjs 기반 웹 페이지에 대한 자동화 된 테스트를 작성하는 데 성공한 사람이 있습니까? 많은 인터넷 검색은 비슷한 문제를 가진 사람들을 찾지 만 답변은 거의 없습니다. 감사!


Ext JS의 좋은 사람들은이 주제에 대해 여기 블로그에 올릴만큼 친절 했습니다 . 이게 도움이 되길 바란다.
NBRed5

답변:


173

Selenium으로 ExtJS를 테스트하는 데있어 가장 큰 장애물은 ExtJS가 표준 HTML 요소를 렌더링하지 않으며 Selenium IDE가 단순히 장식 역할을하는 요소를 대상으로하는 명령을 순진하게 (그리고 정당하게) 생성한다는 것입니다. 보고 느끼다. 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 로케이터를 사용해야하는 경우가있을 수 있습니다.

JavaScript 실행

일부 요소는 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

Selenium에서는 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

필드 검증

정규식 또는 유효성 검사를위한 vtypes가 연결된 양식 필드 (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"))]

"display : none"검사는 오류 필드가 표시된 다음 숨겨져 야하기 때문에 필요합니다. ExtJS는 DOM 트리에서 오류 필드를 완전히 제거하는 대신 단순히 숨길 것입니다.

요소 별 팁

Ext.form.Button 클릭

  • 옵션 1

    명령 : 클릭 대상 : css = button : contains ( 'Save')

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

  • 옵션 2

    명령 : 클릭 대상 : css = # save-options 버튼

    ID로 버튼을 선택합니다.

Ext.form.ComboBox에서 값 선택

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

먼저 값을 설정 한 다음 옵저버가있는 경우 명시 적으로 select 이벤트를 발생시킵니다.



5

블로그 는 저에게 많은 도움 이 되었습니다. 그는 주제에 대해 꽤 많은 글을 썼고 여전히 활동적인 것 같습니다. 그 남자는 또한 좋은 디자인을 높이 평가하는 것 같습니다.

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

특히이 기사 가 매우 유용 하다는 것을 알았습니다 .

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


4

셀레늄으로 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가 자체적으로 생성하지 않도록해야합니다.


Ext.ComponentQuery.query에서 xtype을 사용하여 그리드를 찾을 수 있어야합니다 (그리드에서 확장하고 자신의 그리드에 대해 xtype을 정의했다고 가정). 이에 대한 몇 가지 사항을 추가로 설명했습니다. 또한 xpath를 사용하여 행에 대한 식별 값이 포함 된 td를 찾아서 항목을 클릭 할 수 있음을 발견했습니다
JonnyRaa

4

요소가 표시되는지 감지하려면 다음 절을 사용하십시오. 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')]"

3

extjs 테스트에서 발생하는 문제 유형에 대해 더 많은 통찰력을 제공 할 수 있습니까?

유용한 Selenium 확장 프로그램 중 하나는 waitForCondition 입니다. Ajax 이벤트에 문제가있는 것 같으면 waitForCondition을 사용하여 이벤트가 발생할 때까지 기다릴 수 있습니다.


3

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

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

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

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

findExtJsGridRow("Foo");

... 그웬에서 다음을 수행 할 수 있습니다.

extjsgridrow by text "Foo"

Ext JS 특정 구성 요소로 작업하는 방법에 대한 Java 및 Gwen에 대한 많은 문서가 있습니다 . 문서는 또한 이러한 모든 Ext JS 구성 요소에 대한 결과 HTML을 자세히 설명하며, 유용 할 수도 있습니다.


2

페이지에서 그리드의 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;
    }

2

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

로부터 엽차 문서 :

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

Ext.AbstractComponentonBoxReady메서드를 재정 의하여 사용자 지정 데이터 속성 (이름이 testIdAttr각 구성 요소의 사용자 지정 속성에서 따옴)을 해당 구성 요소의 itemId값 (있는 경우)으로 설정합니다. 파일의 배열에 Testing.overrides.AbstractComponent클래스를 추가하십시오 .application.jsrequires

/**
 * 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를 검색하지 않아도됩니다.


2

셀레늄을 사용하는 테스트 프레임 워크를 개발 중이며 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");
}

1

형식적인 HTML이 아닌 복잡한 UI의 경우 xPath는 항상 신뢰할 수있는 것이지만 ExtJ를 사용하는 다른 UI 구현에 관해서는 약간 복잡합니다.

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

예를 들어 자바 코드에서 :

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

selenium.click(fullXpath);

1

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)]..

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.