블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 받은 트랙백

글 보관함

calendar

          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            


Asynchronous Testing with Protractor’s ControlFlow


Protractor is an end-to-end testing framework for AngularJS applications that uses a real browser, just as a real user would. It is built on top of NodeJS and WebDriverJS and taps into the internals of Angular to know when Angular is done processing and updating bindings.



Protractor는 real user would와 마찬가지로 실제 브라우저를 사용하는 AngularJS 응용 프로그램의 end-to-end testing framework입니다. NodeJS 및 WebDriverJS 위에 구축되며 Angular의 내부를 tap해서 Angular가 바인딩 처리 및 업데이트를 완료 한 시점을 알 수 있습니다.


The joy of Protractorand WebDriverJS is that we can write our tests in a synchronous style, and still have the added benefits of asynchronous code. 


Protractor와 WebDriverJS의 강점은 동기식 스타일로 테스트를 작성할 수 있으며 비동기 코드의 부가적인 이점을 여전히 가지고 있다는 것입니다.

We are currently using Protractor for testing a Rails and Angular application that we’re developing here in the Detroit office. We were faced with a problem: “How do we write our own functions which are asynchronous but appear in the same synchronous style that Protractor tests are written in?” This is especially handy for performing REST requests for seeding data into the test database using something like the rails Hangar gem. 


우리는 현재 디트로이트 사무실에서 개발중인 Rails 및 Angular 응용 프로그램을 테스트하기 위해 Protractor를 사용하고 있습니다. "비동기식이지만 Protractor로 작성된 동기식으로 보이는 함수는 어떻게 작성합니까"  이것은 rails Hangar gem 같은 것을 사용해서 테스트 데이터베이스에 데이터를 넣기 위한 REST requests를 수행 할 때 특히 유용합니다. 


The ControlFlow


This required diving into the internals of how Protractor and WebDriverJS handle asynchrony. WebDriverJS uses an object called theControlFlow, which coordinates the scheduling and execution of commands operating on a queue. 


Any time an asynchronous command is invoked, it’s put in the queue where it will wait for all previous commands to complete prior to execution. The ControlFlow allows us to write code like this:


Protractor와 WebDriverJS가 어떻게 비동기를 처리하는지에 대해 좀 더 깊이 들어가겠습니다. WebDriverJS는 theControlFlow라는 객체를 사용합니다. 이 객체는 queue에서 작동하는 명령의 일정과 실행을 조정합니다.


비동기 명령이 호출 될 때마다 queue에 저장되어 실행 되기 전 모든 이전 명령들이 완료 될 때까지 대기합니다. ControlFlow를 사용하면 다음과 같은 코드를 작성할 수 있습니다.


driver.get(“http://www.google.com”);
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver');
driver.findElement(webdriver.By.name('btnG')).click();
driver.getTitle().then(function(title) {
  console.log(title);
});


That really performs in a synchronous manner such as this:

이것은 아래와 같이 동기화 방식으로 처리 됩니다.


driver.get(“http://www.google.com”).
    then(function() {
      return driver.findElement(webdriver.By.name('q'));
    }).
    then(function(q) {
      return q.sendKeys('webdriver');
    }).
    then(function() {
      return driver.findElement(webdriver.By.name('btnG'));
    }).
    then(function(btnG) {
      return btnG.click();
    }).
    then(function() {
      return driver.getTitle();
    }).
    then(function(title) {
      console.log(title);
    });


Behind the scenes of WebDriver, each call that interacts with the browser, such as get()findElement()sendKeys(), and click(), is being scheduled and pushed onto the WebDriver ControlFlow, allowing us to not have to worry about using .then() on the resulting promises (unless we specifically want the result returned by the call). 

WebDriver의 이면에서 get (), findElement (), sendKeys () 및 click ()과 같이 브라우저와 상호 작용하는 각 호출이 예약되고 WebDriver ControlFlow에 푸시되므로 resulting promises 에 대해 걱정할 필요가 없습니다 (호출에 의해 반환 된 결과가 특별히 필요하지 않는 한)


Using the WebDriverJS Promises



The ControlFlow queues functions based on promises. The following code exhibits how to take a callback based function and wrap it into WebDriver’s Promise API. We will be using the Restler NodeJS library.


ControlFlow 대기열 기능은 promises를 기반으로합니다. 아래 코드는 callback 기반 함수를 WebDriver의 Promise API로 래핑하는 방법을 보여줍니다. 우리는 Restler NodeJS 라이브러리를 사용할 것입니다.

To create a WebDriver/Protractor deferred using their promise API:

promise API를 사용하여 지연된 WebDriver / Protractor를 만들려면 :


deferred = protractor.promise.defer()


Then fullfill or reject the promise based on Restler’s events and return the deferred promise:


restler.postJson(url, requestData, options).once('success', function() {
  return deferred.fulfill();
}).once('error', function() {
  return deferred.reject();
}).once('fail', function() {
  return deferred.reject();
});
 
deferred.promise;


Pushing the Promise Onto the ControlFlow



To solve our problem of invoking a synchronous REST request, we have to interact with WebDriver’s ControlFlow. 

To get the instance of the ControlFlow that is shared with protractor:


synchronous REST request를 invoking하는 문제를 해결하려면 WebDriver의 ControlFlow와 상호 작용해야합니다.

Protractor와 공유되는 ControlFlow의 인스턴스를 얻으려면 :


var flow = browser.controlFlow()


Then we can use the ControlFlow’s execute() function, assuming we created a based on the above code that wraps restler’s callbacks and returns a WebDriverJS promise:


그런 다음 Restler의 콜백을 래핑하고 WebDriverJS 약속을 반환하는 위 코드를 기반으로 ControlFlow의 execute () 함수를 사용할 수 있다고 가정합니다.


flow.execute(restFunction)


Chaining Promises and Getting Results



The good news is that ControlFlow’s execute() function returns a new promise that will be fulfilled when our original promise is executed by the scheduler. We can use use the all() function, which returns a new promise once all of the control flow’s promises are fulfilled:

좋은 소식은 ControlFlow의 execute () 함수가 새 promise를 반환한다는 겁니다. 이렇게 함으로서 원래 약속이 스케줄러에 의해 실행될 때 수행 될 이 조건이 충족되게 됩니다. 모든 control flow의 promises가 충족 됐을 때 new promise 가 반환되는 all () 함수를 사용할 수 있습니다.


var allPromise = protractor.promise.all(flow.execute(restFunction1), flow.execute(restFunction2))



When allPromise is fulfilled, it will return an array of the results of all the promises passed to all() as arguments. 

allPromise가 수행되면 all ()에 전달 된 모든 promises의 결과 배열을 인수로 반환합니다.


Ideally the implementation of your helper functions would abstract the intermediary promises that are being passed to the ControlFlow and purely operate based upon the promises returned from the ControlFlow’s execute function.

이상적으로 helper 함수의 구현은 ControlFlow로 전달되는 intermediary promises을 abstract화하고 ControlFlow의 실행 함수에서 반환 된 promises를 기반으로 작동합니다.


저작자 표시 비영리 동일 조건 변경 허락
신고