안녕하세요 Selenium - Web Driver ( Node.js Version ) 에서 SendKeys 에 대해서 간단하게 알아 보려고 합니다.
처음에 SendKeys 에 대해서 사용하게 되는 경우 대부분 자동화 도중에 어떠한 값을 "입력" 하게 되는 경우에
사용하게 되면서 시작 하게 될 것 같습니다.
// DOM select targetElement
let targetElement = driver.findElement(By.css('div .target'));
// targetElement input String
await targetElement.sendKeys('Automation Input');
하지만 위와같은 방식 말고 다른 방법으로도 사용이 가능합니다.
Automation Copy and Paste with SendKeys
// DOM select targetElement
let targetElement = driver.findElement(By.css('div .target'));
// targetElement input String
await targetElement.sendKeys('Automation Input');
// Copy and Paste One Take
await targetElement.sendKeys(Key.CONTROL,'a'); // All Select String
await targetElement.sendKeys(Key.CONTROL,'c'); // Block String to Copy
await targetElement.sendKeys(Key.CONTROL,'v'); // Paste
뭔가 해당 사항만 봤을 때는 'Automation Input' 이 입력되면 Automation Input 이 들어가고
앞에 Control 값이 있을때 해당 값과 키 값을 같이 누르는 것처럼 보입니다.
하지만 실제로는 어떻게 동작하는지 알면 왜 위와 같이 동작하는지 이해하기 편합니다.
위의 예시코드는 WebElement.sendKeys 였지만 실제로는 Actions 객체로도 가능한데요
이번 포스팅에서는 WebElement.SendKeys 지만 Actions의 SendKeys 도 비슷한 부분들이 많아
우선 Actions의 SendKeys 부터 간단하게 열어 보았습니다.
// Selenium github
Selenium 은 오픈소스 이다 보니까 코드 가 공개 되어있는데요
SendKeys 의 구현체를 발췌 해 보았습니다.
sendKeys(...keys) {
const actions = [];
for (const key of keys) {
if (typeof key === 'string') {
for (const symbol of key) {
actions.push(
this.keyboard_.keyDown(symbol),
this.keyboard_.keyUp(symbol));
}
} else {
actions.push(
this.keyboard_.keyDown(key),
this.keyboard_.keyUp(key));
}
}
return this.insert(this.keyboard_, ...actions);
}
1. sendKeys(...keys) -> ...keys 로 spread 연산자 입니다. 들어오는 모든 키들을 파라미터로 받습니다.
이부분이 이해가 안될수 있는게
function sendKeys(keys){
console.log(keys); // automation
}
sendKeys('automation');
이와같은 형태 아닌가? 라고 잠깐 착각 할수 있습니다. 하지만 Spread Operator 를 사용하게되면 조금 이야기가 달라 질 수 있습니다.
function sendKeys(...keys){
console.log(keys); // ['automation']
}
sendKeys('automation');
위와의 차이점은 배열(Array) 로 들어온다는 점입니다. 이 뜻은
A, automation 과같이 입력이 된다는 뜻이 됩니다.
function sendKeys(...keys){
console.log(keys); // ['CONTROL_A','automation']
}
sendKeys('CONTROL_A','automation');
미리 정의해둔 컨트롤(Control) 이나 쉬프트 (Shift) 값이 들어왔을때 조합키 형태로 사용할 수 있도록
여기에서 잠깐 보고 가야 할 부분이 위에 Key.CONTROL 은 lib/input 에 선언이 되어있기 때문에 사용하기 위해서
코드의 최상단에
const { Key } = require('selenium-webdriver/lib/input');
로 가져오신 후 사용하시면 됩니다.
위와같이 되어있기 때문에 사용하고 싶은 부분들을 사용하시면 됩니다.
이제 SendKeys 에서 입력 키들을 배열로 받을수 있도록 처리가 되어 있습니다.
간단하게 CONTROL 만 선언해서 돌려 본다면
var Key = {
CONTROL : '\uE009'
}
function sendKeys(...keys){
const actions = [];
for(const key of keys){
if(typeof key==='string'){
for(const symbol of key){
console.log(`symbol ${symbol}`);
}
}
else{
console.log(`not Symbol ${key}`);
}
}
}
sendKeys(Key.CONTROL,'automation');
보시면 CONTROL 부분은 심볼로 처리되고 그 외에 있는 문자열들은 따로따로 나눠서 되어있습니다.
미리 선언해놓은 심볼들은 내부적으로 다시 연결하여서 그에 맞는 조합키를 입력 합니다. (해당 내용은 이번 포스팅에서는 제외하고 하겠습니다.)
그리고 해당 값들을 통해서 KeyDown 과 KeyUp을 사용하여 진행합니다.
"Automation" 이 파라미터로 넘어간다면
A Key Down
A Key Up
u Key Down
u Key Up
.... 이 순서로 진행이 된다고 볼수 있습니다.
그래서 테스트 해 보았습니다.
// 첫번째 요소에 Shift 키와 함께
await targetElement.sendKeys(Key.SHIFT,'automation');
// Result : AUTOMATION
// 두번째 요소에 소문자 입력시
await subtargetElement.sendKeys('automation');
// Result : automation
위처럼 현재 Element 에 조합키 + 소문자 입력후 다른 Element 에 automation 만 입력시 어떻게 될지 확인해보았을 시
입력중인 위젯에 대해서는 Shift키 심볼로 인해 keyDOWN 상태가 유지되어 대문자로 나오지만
새롭게 지정된 요소에서는 해당 키 내용이 없기 때문에 소문자가 그대로 나타납니다.
this.sequences_ = new Map([
[this.keyboard_, []],
[this.mouse_, []],
]);
insert(device, ...actions) {
this.sequence_(device).push(...actions);
return this.sync_ ? this.synchronize() : this;
}
위의 sendKeys 마지막 부분 요소에 보면 insert하는 부분이 있게 되는데요 위의 코드는 Selenium 자체코드입니다.
Actions.SendKeys 의 경우 관련된 액션과 키 값들을 정리 후 한꺼번에 리턴합니다.
Actions의 경우 perform 이 호출될시 리턴된 액션들을 순차적으로 실행하는 형태이기 때문에 그때 순차적으로 실행됩니다.
WebElement의 SendKeys 의 경우
async sendKeys(...args) {
let keys = [];
(await Promise.all(args)).forEach(key => {
let type = typeof key;
if (type === 'number') {
key = String(key);
} else if (type !== 'string') {
throw TypeError('each key must be a number of string; got ' + type);
}
// The W3C protocol requires keys to be specified as an array where
// each element is a single key.
keys.push(...key.split(''));
});
if (!this.driver_.fileDetector_) {
return this.execute_(
new command.Command(command.Name.SEND_KEYS_TO_ELEMENT)
.setParameter('text', keys.join(''))
.setParameter('value', keys));
}
keys =
await this.driver_.fileDetector_.handleFile(
this.driver_, keys.join(''));
return this.execute_(
new command.Command(command.Name.SEND_KEYS_TO_ELEMENT)
.setParameter('text', keys)
.setParameter('value', keys.split('')));
}
위와 같은 형태를 띄고있는데요 Actions 과 유사한점이 있지만 다른점이 있다면 바로 Command 를 통해서 실행한다는점입니다.
눈에 띄는 것은 맨 첫줄에 Promise all 부분인데요 들어오는 키 형태중에 조합형태로 Promise 를 리턴하는 경우가 있을 경우에 대비해서 만들어 놓은 것으로 보입니다.
위에서 Shift를 눌러놓은 상태에서 automation 시 AUTOMATION 으로 나온후 타 요소에 갈땐 다시 SHIFT가 없는 상태였는데요
한 요소에서 같이 될 경우
await targetElement.sendKeys(Key.SHIFT,'automation'); // AUTOMATION
await targetElement.sendKeys('ppap'); // ppap
위와같이 보시면 Commander에서 실행 후 다시 초기화가 되는형태로 보여집니다.
마지막 궁금했던 테스트입니다.
await targetElement.sendKeys(Key.CONTROL,'a',Key.CONTROL,'c',Key.CONTROL,'v','v');
await targetElement.sendKeys(Key.CONTROL,'a','c','v','v');
그럼 한줄로 그냥 할수 있을거같은데 어떻게 동작하나 보았습니다.
실제로 이번에 포스팅한 계기는 복사 붙여넣기 자동화 케이스를 만들다가 작성하게 된 경우입니다.
그렇기 때문에 on-copy 와 on-paste 의 이벤트가 Callback 되는지에 중점을 두게 되는데
위의 2케이스 전부 콜백은 동작합니다. v를 한번 더 넣은 경우를 붙여넣기가 블록상태에선 블록만 해제되니까 테스트용으로 두번 넣었습니다. (붙여넣기 확인용)
1번 케이스의 경우 결과가 c 로만 나타나게 됩니다.
Ctrl 누르고 a -> 전체 블록 지정 ( 중요하게 보아야 할점은 KeyDOWN 이라는 점 )
다시 Ctrl 누르고 c ( 한번 더 눌렸기 때문에 keyDOWN Ctrl 이 UP이 되고 c만 입력 )
다시 Ctrl 누르고 v ( 다시 누르면서 붙여넣기 )
결과 : 몇몇 Text 관련 Element 에서는 focus를 주고 난 후에 입력이 되는 경우가 있어서 저는 위처럼 focus를 주고 입력합니다.
긴글 읽어주셔서 감사합니다!!
// focus in Textarea
await this.driver.executeScript('arguments[0].focus();',targetElement);
await targetElement.sendKeys(Key.CONTROL,'a','c','v');
'QA_자동화_UI_Automation > Selenium-WebDriver' 카테고리의 다른 글
Jenkins 와 Selenium 을 사용한 웹 자동화(web Automation Test) (0) | 2018.11.07 |
---|---|
[Selenium-웹자동화] async Iterator 유의사항 ( findElements By.css ) (0) | 2018.08.31 |
[Selenium-웹자동화] Error - UnsupportedOperationError [IE11] (0) | 2018.08.21 |
[Selenium-웹자동화] Naver Login 페이지 변경에 따른 예제 변경(Chrome) (18) | 2018.08.21 |
[Selenium-웹자동화] Naver Login 페이지 변경에 따른 예제 변경 안내 (0) | 2018.07.24 |