개요
웹엘리먼트가 지원하는 sendKey와 click은 간단히 쓰기엔 편리하지만 정교한 인터렉션을 재현하지는 않습니다.
셀레늄은 거의 완벽한 이벤트를 재현할 수 있는데 이를 찬찬히 살펴보겠습니다. #3에서는 기본 이벤트 입문만 진행하고 이에 맞춰 worker.js와 reporter.js도 약간씩 변경하는 정도만 진행해보죠. #4에서 본격적인 이벤트처리로 가기 전에 기초학습이라 생각하시면 될 듯합니다.
ActionSequence
ActionSequence는 실행할 이벤트를 체이닝으로 모아뒀다가 일괄로 perform()을 이용해 실행합니다. 이에 해당되는 터치이벤트처리기는 TouchSequence입니다. 이를 직접 생성하여 인자에 드라이버를 넘기는 스타일로 만들 수도 있습니다.
const ActionSequence = require('selenium-webdriver/lib/actions').ActionSequence; const TouchSequence= require('selenium-webdriver/lib/actions').TouchSequence; const action = new ActionSequence(driver); const touch = new TouchSequence(driver);
하지만 보단 편리하게 driver의 actions() 메소드와 touchActions()메소드를 통해 생성하면 됩니다.
const action = driver.actions(); const touch = driver.touchActions();
간단한 마우스오버 테스트를 위해 여태 잘 사용하던 test1.html을 약간 수정해보죠.
<!doctype html> <html> <head> <meta charset="utf-8"> <title>test1</title> <style> a{font-size:12px} a:hover{font-size:20px} </style> </head> <body> <div id="test1">abc</div> <a id="test2">link</a> </body> </html>
추가된 부분은 style과 a태그로 오버시에 font-size:20px가 되도록 조정해두었습니다. 이제 test2항목에 마우스를 옮겨둔 뒤 font-size를 조사하면 ’20px’가 나와야겠죠.
worker.js 수정
이번에는 그냥 날로 짜지 않고 처음부터 worker.js를 수정한 뒤 진행해보겠습니다.
const wdMain = require('selenium-webdriver'), By = wdMain.By, until = wdMain.until; const wd = require('selenium-webdriver/lib/webdriver'); const Driver = require('selenium-webdriver/chrome').Driver; const DRIVER = Symbol(); module.exports = class{ constructor(url){ this[DRIVER] = new Driver(); this[DRIVER].get(url); } element(css){ return this[DRIVER].findElement(By.css(css)); } elements(css){ return this[DRIVER].findElements(By.css(css)); } waitUntil(time, method, ...arg){ return this[DRIVER].wait(until[method](...arg), time); } waitElement(time, title, f){ return this[DRIVER].wait(new wd.WebElementCondition(title, f), time); } waitCondition(time, title, f){ return this[DRIVER].wait(new wd.Condition(title, f), time); } by(method, v){ return By[method](v); } get action(){ return this[DRIVER].actions(); } get touch(){ return this[DRIVER].touchActions(); } };
복습겸 전체 코드를 꺼냈지만 실제 변경된 부분은 하단에 추가된 action과 touch메소드 뿐입니다. 이제 worker를 이용하여 간단히 action을 생성할 수 있으니 이를 이용해 위에 계획했던 테스트를 진행해보죠.
const Reporter = require('./reporter.js'); const reporter = new Reporter('https://www.bsidesoft.com/hika/wp/2196/report.html'); const Worker = require('./worker.js'); const worker = new Worker('https://www.bsidesoft.com/hika/wp/2196/test1.html'); worker.action.mouseMove(worker.element('#test2')).perform(). then(v=>worker.element('#test2').getCssValue('font-size')). then(v=>reporter.report(`(v = '${v}') == '20px' :: ${v == '20px'}`));
코드를 보면
- worker로부터 action을 얻어,
- 마우스를 옮길 대상을 ‘#test2’로 지정한 뒤 perform()을 했습니다.
- 이 결과 Promise가 발생되고 다음 then에서 ‘#test2’에게 getCssValue를 이용해 font-size를 물어보죠.
- 마지막으로 ‘font-size’의 값이 마지막 then의 v로 들어오게되고 레포터에게 적절하게 표현하여 보내줍니다.
결과는 다음과 같은 모습일 것입니다.
레포터가 단순히 텍스트만 받아주다보니 report시에 worker쪽에서 할 일이 많습니다. reporter에도 간단한 assert를 추가해주도록 하죠.
const wd = require('selenium-webdriver'); const Driver = require('selenium-webdriver/chrome').Driver; const DRIVER = Symbol(); const format = v=>typeof v == 'string' ? "'" + v + "'" : v; const result = v=>`<span style="font-size:20px;color:#${v ? '0a0' : 'a00'}">${v}</span>`; module.exports = class{ constructor(url){//보고용 url지정 this[DRIVER] = new Driver(); this[DRIVER].get(url); Object.freeze(this); } report(value){ this[DRIVER].executeScript( `document.getElementById('report').innerHTML += "<li>${value}</li>";` ); } assert(title, value, expect){ const v = [ '<li>', `<h3>${title}</h3>`, `<div>value:${format(value)} == expect:${format(expect)}</div>`, `<div>${result(value === expect)}`, '</li>' ].join(''); this[DRIVER].executeScript(`document.getElementById('report').innerHTML += "${v.replace(/["]/g,'\\"')}";`); } quit(){ //종료시킴 this[DRIVER].quit(); } };
새로 추가된 assert는 인자로 제목, 값, 기대하는 값을 받아서 이를 적절하게 태그로 구성해줍니다. 약간의 디자인을 위해 format함수와 result함수가 동원되었습니다.
이를 이용한 test.js는 다음과 같이 변경됩니다.
const Reporter = require('./reporter.js'); const reporter = new Reporter('https://www.bsidesoft.com/hika/wp/2196/report.html'); const Worker = require('./worker.js'); const worker = new Worker('https://www.bsidesoft.com/hika/wp/2196/test1.html'); worker.action.mouseMove(worker.element('#test2')).perform(). then(v=>worker.element('#test2').getCssValue('font-size')). then(v=>reporter.assert('mouseMove Test', v, '20px'));
마지막 줄에서 훨씬 직관적인 단정표현이 되었음을 알 수 있습니다.
결과화면도 보다 이뻐집니다 ^^
결론
셀레늄의 이벤트는 굉장히 강력합니다. 이제 편리하게 쓰고 확인할 수 있는 기초를 갖췄으니 #4에서는 다양한 이벤트를 심도있게 테스트해보죠.
recent comment