IE 버전입니다. 

 

트러블 슈팅 

 

현재 capabilities 가 동작하지 않는데 

1. 이그노어프로텍티드모드 세팅 true

2. 이그노어줌세팅 true

 

2개가 있는데 이유는 IE는 줌 100% , 보안에서 보호체크가 전부되어야 하기 때문이다.

이거를 코드상으로 무시를 하고 킬수가있는데 일단 코드상은 안되니

 

IE에서 직접 설정 후 코드를 돌려보시기 바랍니다.

 

iframe (IE의 경우는 swtichTo.frame('string') 이 되지않아

 iframe을 직접 찾아서 WebElement를 넘겨주어야 합니다.  (IE상의 이벤트 사이클 문제로 인함)

 

 

결과 코드 

 

 

 

 const _url = "https://www.naver.com/";    require('iedriver'); const webdriver = require('selenium-webdriver'); const {By,Util}  = webdriver; // 드라이버 빌드 // IE const Capabilities = require('selenium-webdriver/lib/capabilities').Capabilities; let capabilities = Capabilities.ie(); capabilities.set('ignoreProtectedModeSettings', true); capabilities.set('ignoreZoomSetting', true); capabilities.set('IgnoreZoomLevel', true); const driver = new webdriver.Builder().withCapabilities(capabilities).build();   const register_pc = false; (async () => {   try {     // 페이지 이동     await driver.get(_url);         // 윈도우 최대화  headless 옵션 사용시 는 의미없음     await driver.manage().window().maximize();     // input값 가져옴     let inputId = await driver.findElement(By.css('input#id'));     // ID 입력         await inputId.sendKeys('myID');     // password 값 가져옴     let inputpw = await driver.findElement(By.css('input#pw'));     // password 입력         await inputpw.sendKeys('mypw');     // login 버튼 가져와서 클릭          let loginBtn = await driver.findElement(By.css("input[type='submit']"));         await loginBtn.click();       // 최초 실행 PC일 경우 해당 페이지가 나타나기 때문에 존재한다면 등록 유무 선택     let page_ = await driver.findElements(By.css('fieldset.login_form a'));       if(!!page_){             // 등록 page_[0] 등록 안함  page_[1]             !!register_pc ?console.log("등록합니다.") :await page_[1].click();       }        await driver.sleep(2000);           // selenium-js 에서는 switchTo.frame을 통해서 프레임을 변경 한다.       console.log("프레임 변경");     await driver.sleep(5000);       await driver.switchTo().frame(await driver.findElement(By.id("minime")));     // 변경 후 프로필에 메일을 가져오고 클릭        let mail_profile = await driver.findElement(By.id('mail_count_profile'));       //  메일 클릭        //  화면 제어가 빠른 경우에 대한 sleep -> 추후 isContentsLoaded 또는 WebElement Condition 으로 변경         console.log(await mail_profile.getAttribute('href'));        await driver.sleep(1500);       await mail_profile.click();   //   // 기존 프레임으로 다시 돌아오는 경우 (page이동이없었을때)      //   //   await driver.switchTo().defaultContent();   //   // 임시 테스트용 Sleep      await driver.sleep(2000);     console.log(await driver.getTitle());     console.log(await driver.getCurrentUrl());     let newUrl = await driver.getCurrentUrl();     await driver.navigate().to(newUrl);   // // 가장 최상단 메일 의 Subject를 가져옴     let mailTitle = await driver.findElement(By.css('ol.mailList.sender_context li .subject'));   // // 셀레니엄 JS에서 getText는 innerText를 가져온다고 되어있습니다.    console.log(await mailTitle.getText());    // 페이지 뒤로가기    // await driver.navigate().back();         }    catch(err){     // Node Debug시 메시지가 너무길어 한글로 처음과 끝을 지정해서 보여지기 쉽게 처리      console.log("자동화 도중 에러 ",err  +  " 에러메시지 끝  ");   }   finally {         await driver.sleep(3000);         await driver.quit();   } })();   

 

 

 

저번에 UI 자동화에 대한 개요(?) 정도로만 시작했으며

 

이번에는 메일까지 접속해서 확인하도록 하겠습니다.

 

ID를 가져와서 입력하는 부분 및 PW를 가져오는 부분은 생략 하겠습니다.

 

전 포스팅에서 다루었기 때문에 

 

id와 pw를 입력해서 로그인 까지 하게되면

 

const _url = "https://www.naver.com/";  require('chromedriver'); const webdriver = require('selenium-webdriver'); const {By,Util}  = webdriver;   var driver = new webdriver.Builder() .forBrowser('chrome') .build();   const register_pc = false; (async () => {   try {     await driver.get(_url);           await driver.manage().window().maximize();     let inputId = await driver.findElement(By.css('input#id'));         await inputId.sendKeys('myID');     let inputpw = await driver.findElement(By.css('input#pw'));         await inputpw.sendKeys('mypassWord');     let loginBtn = await driver.findElement(By.css("input[type='submit']"));         await loginBtn.click();      let page_ = await driver.findElements(By.css('fieldset.login_form a'));    // 최초 실행 PC일 경우 페이지가 나타남        if(!!page_){             // 등록 page_[0]             // 등록 안함  page_[1]             !!register_pc ?console.log("등록합니다.") :await page_[1].click();       }               }    catch(err){     console.log("자동화 도중 에러 ",err  +  " 에러메시지 끝  ");      }   finally {         await driver.sleep(2000);         await driver.quit();   } })(); 

 

해당과 같이 코드를 작성후 node test.js 를 실행할시에 로그인 까지는 정상적으로 됩니다.

 

그후에 내 로그인 프로파일에 메일 이라는 부분을 클릭하여서 이동을 하여야 디는데 iframe 특성상

 

일반 DOM 과 분리되어있는 독립 document이기 때문에 클릭이 되지않습니다.

-> 정확히는 WebElement를 가져오지 못합니다.

해당 내용을 해결하기 위해서는 selenium-js에 있는 swtichTo 라는 API 를 사용하여야 합니다.

 

아래의 이미지는 네이버 로그인 프로필은 iframe으로 감싸져있음을 나타냅니다.

 

Native JavaScript 역시 iframe에 접근할 때는

window.frames["minime"].document.getElementById("mail_count_profile");

이와같이 사용합니다. 

[iframe] 

 

 

 

결과 코드

 

 

 const _url = "https://www.naver.com/";  // require 가 Builder보다 위에 있어야 함 공식 홈페이지  require('chromedriver'); const webdriver = require('selenium-webdriver'); const {By,Util}  = webdriver;  // 드라이버 빌드  var driver = new webdriver.Builder() .forBrowser('chrome') .build();   const register_pc = false; (async () => {   try {     // 페이지 이동     await driver.get(_url);         // 윈도우 최대화  headless 옵션 사용시 는 의미없음     await driver.manage().window().maximize();     // input값 가져옴     let inputId = await driver.findElement(By.css('input#id'));     // ID 입력         await inputId.sendKeys('id');     // password 값 가져옴     let inputpw = await driver.findElement(By.css('input#pw'));     // password 입력         await inputpw.sendKeys('pw');     // login 버튼 가져와서 클릭          let loginBtn = await driver.findElement(By.css("input[type='submit']"));         await loginBtn.click();       // 최초 실행 PC일 경우 해당 페이지가 나타나기 때문에 존재한다면 등록 유무 선택     let page_ = await driver.findElements(By.css('fieldset.login_form a'));       if(!!page_){             // 등록 page_[0] 등록 안함  page_[1]             !!register_pc ?console.log("등록합니다.") :await page_[1].click();       }     // selenium-js 에서는 switchTo.frame을 통해서 프레임을 변경 한다.        await driver.switchTo().frame('minime');     // 변경 후 프로필에 메일을 가져오고 클릭        let mail_profile = await driver.findElement(By.id('mail_count_profile'));       //  메일 클릭        //  화면 제어가 빠른 경우에 대한 sleep -> 추후 isContentsLoaded 또는 WebElement Condition 으로 변경        await driver.sleep(1500);       await mail_profile.click();     // 기존 프레임으로 다시 돌아오는 경우 (page이동이없었을때)        //   await driver.switchTo().defaultContent();     // 임시 테스트용 Sleep      await driver.sleep(2000);     console.log(await driver.getTitle());     console.log(await driver.getCurrentUrl());     let newUrl = await driver.getCurrentUrl();     await driver.navigate().to(newUrl);   // 가장 최상단 메일 의 Subject를 가져옴     let mailTitle = await driver.findElement(By.css('ol.mailList.sender_context li .subject'));   // 셀레니엄 JS에서 getText는 innerText를 가져온다고 되어있습니다.    console.log(await mailTitle.getText());    // 페이지 뒤로가기    // await driver.navigate().back();         }    catch(err){     // Node Debug시 메시지가 너무길어 한글로 처음과 끝을 지정해서 보여지기 쉽게 처리      console.log("자동화 도중 에러 ",err  +  " 에러메시지 끝  ");   }   finally {         await driver.sleep(2000);         await driver.quit();   } })();    

 

 

저는 네이버 알림을 켜놔서 새로운 기기 에서 로그인되었다는 창이 계속 나타나네요 

 

 

 

 

 

 

 

// ** 2019-02-27

localhost: 를 사용할때 발생하는 이슈로 localhost에 대한 매핑이 PC마다 다르기 때문에 발생하게 되는 것으로 보입니다.


127.0.0.1 로 수정


//

UnhandledPromiseRejectionWarning: Error: Server terminated early with status 1


 session not created exception

from disconnected: unable to connect to renderer


SessionNotCreatedError


셀레니엄 lib는 실행시에 웹 드라이버르 통해서 실행하게 되는데 (driver를 require에서 사용시)


가끔 해당 에러로 인해 실행이 되지않는 경우가 있습니다.


급한대로 


코드에서


require('chromedriver') 부분은 잠시 주석처리하고 실행했다가

다시


주석을 풀면되는데


이부분에서 주석을 제거하면 실행되는점도 이상하고


생각보다 많이 이상한거같은데


일단은 현재 저 방법으로 해결이 됩니다.


급한대로 적어 놓고


확실한 동작 원리나 방식등은 조사하고 다시 포스팅 하겠습니다.


webUI 테스트 자동화 (E2E 테스트 end to end)

 

UI 테스트 자동화 관련된 키워드

phantom.js && casper.js, zombie.js, slimer.js ,node.js, webdriver.io, Cucumber.js, protractor ,nightwatch.js, htmlUnit,Guitar , selenium , webdriver,javascript,Cypress.io,uitest.js,uirecorder,testCafe(*typeScript를 사용)    + assertiong lib (chai.js)

 

 

1. Headless Browser (헤들리스 브라우저)

정확히는 헤들리스 브라우저 라기보단 헤들리스 옵션으로 사용할수 있는 lib 들을 표현하였습니다.

헤들리스 옵션은 자동화 테스트 진행시에 UI 없이 브라우저가 실행되게 하는 옵션 입니다. PhantomJS의 CapserJS는

PhantomJS 를 조금 더 세밀하게 제어할수 있는 lib 입니다. 

장점에 셀레니움 이슈들이 존재 하지 않는다고 되어 있는 부분들은  셀레니엄 IDE(Java)등에서 사용되는 여러 방법이 있는데 해당 에서 발생하는 side-effect 들에 대한 이슈없이 단순히 lib에서 발생하는 이슈만 있기 때문에  조금 더 최적의 상태? 를 사용할수 있다고는 하지만 실제로 다 써본건 아니니 참고만 하려고합니다.

 

 

2. 셀레니움 의존 

 

셀레니엄 관련 lib들을 가져와서 사용하는 것으로 Python,Ruby,Java,C#,js (vanilla)

js말고도 다른 언어들이 셀레니엄 lib를 통해서 사용할수 있는 것으로 여러 맞는 언어들을 나에게 맞게 사용할수 있는 장점이 있기 때문에 원하시는 언어로 사용해보시면 될것 같습니다.

 

저는 JS를 현재 공부중에 있다보니 js기반인 selenium-webdriver npm 에서 받아서 사용 하겠습니다.

 

기존에 UI 자동화를 위해서 이것저것 사용은 해봤습니다. guitar라든지 관련 자동화 스크립트 등등

 

하지만 결국 자동화를 위해서 는 코드를 기반으로 짜주어야 하며 위에서와 같이 pyhton,ruby,java,C# 너무많이 있습니다.

 

사실 js를 사용하기 때문에 했다기보다는 Node.js위에서 npm 을 통한 자동화 테스트 코드를 만드는것이 가장 유연성이 

 

높다고 판단되었기 때문입니다.  

 

실제로 자동화에 접목시키기 위해서 아는 지식선에서는 js가 가장 좋아보였습니다.(정확히는 데이터 전송등 유연하다고 생각되었습니다.)

 

그래서 일단 간단하게 Naver Login 후에 메일 에 대한 내용을 가져오는 방법에 대해서 작성하려고 합니다. 

 

우선 오늘은 기본 설정 후 네이버 메인에서 Login 버튼을 클릭 하려고 합니다. 

 

3. Total Test Case

 

1. www.naver.com 으로 접속 (테스트하는 브라우저로)

 

2. id 란 id 입력

 

3. pw 란 pw 입력

 

4. login 버튼 클릭

 

5. 메일 메뉴 클릭

 

6. 가장 최상단 메일 클릭 

 

7. contents 가져오기 

 

8. 로그아웃 

 

어떻게 보면 1~4까지가 Login 에 대한 자동화 Test Case 라고 볼수 있다. 

 

4. Environment Set ( 환경 설정 )

 

우선 Java Script run-time 설치를 위한 https://nodejs.org/en/ 에 들어가서 Node.js를 설치 합니다.

 

LTS 와 Current 에 대한 설명은 생략 하도록 하겠습니다.

 

비트에 맞게 설치 후 자동화 테스트 프로젝트로 사용할 폴더를 하나 지정합니다.

 

저는 바탕화면에 자동화라는 폴더를 만들었습니다.

 

cmd 에서 해당 경로로 이동 후에 npm init 명령어를 통하여서 기본 설정을 행합니다.

 

npm init에 대해서는 따로 포스팅하겠습니다.

 

그리고 일단 크롬테스트를 위하여 설치 하여야 하는 2개의 npm 모듈을 설치합니다.

 

//셀레니엄 드라이버

npm i selenium-webdriver

 

// 크롬 드라이버

npm i chromedriver

 

설치 후 코드를 짜기전에 확인하여야 하는 docs가 있습니다.

 

http://seleniumhq.github.io/selenium/docs/api/javascript/index.html

 

셀레니엄 docs 공식 홈페이지인데요 해당 docs만 보고나서도 셀레니엄으로 어지간한 작업은 다 해결이 됩니다.

 

 

브라우저 실행 및 기본 동작 

 const _url = "https://www.naver.com/"; const webdriver = require('selenium-webdriver'); const {By,Util} = webdriver; require('chromedriver');  var driver = new webdriver.Builder() .forBrowser('chrome') .build();   (async () => {     try {     await driver.get(_url);          } finally {     await driver.sleep(2000);     await driver.quit();     } })();       

 

간단 설명이자면  우선적으로 _url 로 어떤 url 에접속할지 정하게 됩니다.

그리고 테스트를 위한 selenium-webdrvier를 가져오게 되구요.

 

해당 selenium 에서 사용되어지는 유틸 객체들(By,Util)을 가져옵니다. By의 경우는 DOM 조작에 대한 작업이 많기 때문에 자주 쓸일이 많을 겁니다.     그리고 크롬 드라이버를 사용할 것이기 때문에 chromedriver를 require로 가져옵니다.

 

테스트용이기 때문에 IIFE 즉시 실행함수로 바로 실행하게 하였습니다.

 

여기서 주의할 점이   await driver.get(_url); 부분인데요 

 

Selenium-JS 에서 사용되어지는 모든 객체들은 webElement 이며 Promise 객체입니다. JS에서 Promise에 대한 지식이 없다면 사용하기가 애매할수 있기 때문에 비동기 호출과 Promise에 대해서는 꼭 숙지가 되어야 합니다.

 

또한 Promise가 아니라면 async await(ES8) 도 숙지가 되어야 합니다. Promise then(ES6) 보다는 async await가 조금더 가독성이 높기 때문에 저는 async await 방식을 사용하겠습니다.  자세한 설명빼고 말씀드리자면

 

async function 으로 선언후 Promise 객체들을 그냥 리턴받게 되면 Promise<pending> 으로 리턴이되어 리턴된 비동기 함수 에대한 보장을 받지 못합니다. 그렇기 때문에

 

await를 통해서 비동기 함수에 대한 리턴을 보장받게 되는데 해당 await를 사용하기 위해서는 함수를 async로 선언하여야 합니다.

 

그렇기 때문에 위와같이 선언이되었으며 async await를 사용시에 try block 을 만들지 않게 되면 UnHangle Promise ~ 에러가 나타나기 때문에 해당의형식을 취해주어야 합니다.

 

이제 네이버에서 입력하거나 클릭을 위해서 태그를 가져오는 방법에 대해서 생각 해보겠습니다.

 

단순 자동화 클릭만해서는 자동화라고 할수가 없지만 하나하나 차근차근히 진행 하도록 하겠습니다.

 

 

 

순서는 이와같습니다. 주황색 부분에 id를 입력 -> 파란색 박스에 pw를 입력 -> 1과 2과 되었을 경우 빨간색 버튼에 대해서 클릭을 하게 됩니다.

 

그러면 해당 input 과 button 을 어떤식으로 객체를 가져와서 조작을 해야 할지 고민이 되는 상황에서 네이버 페이지를 직접 들어가 보는게 제일 좋습니다.

 

 

사진이 잘 작아서 보이진 않지만 입력 하는 id박스에는

 

<div class="input-box">로 감싸져 있으며 내부값은

label 과 input으로 이루어져있습니다. 우리가 직접 입력하는 부분은 당연히 input 태그일 거고 아래와 같이

 

document.querySelector('input#id').value='login 입니다.'; 라고 개발자 도구에 쳤더니 id칸에 입력이 된점이 확인됩니다.

 

 // ID 입력 document.querySelector("input#id").value="test";  // 패스워드 입력 document.querySelector("input#pw").value="test"; 

 

위의 DOM (돔) 조작을 위한 방식이 있지만 이 방식이 Selenium_JS에서는 되지않을것 같습니다. 그래서 해당 lib의 코드로 수정을 해보자면

  let input_id = await driver.findElement(By.css('input#id')); let input_pw = await driver.findElement(By.css('input#pw')); 

  와같이 수정이 가능 하다. driver.findElement 현재 드라이버 (현재화면) 에서 By.css( selector ) 의 맞는 객체를 가져옵니다.

xPath 또는 findElement(By.id( id ))방식도 있고 docs를 확인하시면 제어 방법은 여러가지가 있습니다.

 

 

입력은 다음에 하도록 하고 login 버튼 까지 클릭을 하도록 하겠습니다.

 

여기서 로그인 버튼은 <span class="btn_login">

                                       <input type="submit" > 해당 버튼입니다.

 

여기서 이제 객체를 가져오는 방법은 완전한 개인의 차이 라는 점을 보여드리고자 합니다.

버튼의 위치를 봅니다 ( 물론 가장 확실하게 가져온다는 가정하에 입니다.)

 <span class="btn_login">         <input type="submit" title="로그인" value="로그인" data-clk="nmy.login"> </span> 

저 가운데 버튼 클릭을 어떤식으로 할수 있을까 라고 말하고 결론부터 말씀드리면 아래의 4가지 방식이 우선 떠 올랐습니다.   해당 방식으로 잘 가져와짐도 확인이 되었으며  그냥 여러 방식이 있다는 점을 보여 드리고 싶었습니다.

 

<토막 상식  data-clk 는 HTML5에서 제공되어지는 data-* 으로 커스텀 프로퍼티를 사용하기 위함입니다.>

CSS 셀렉터를 정말 무궁무진하기떄문에 어떠한 방식으로도 객체를 가져와서 사용할수 있음을 알면 됩니다.

 

해당 코드를 node test.js로 실행시 네이버를 열고 -> 바로 login 버튼을 클릭 하기 때문에 id를 입력하라는 tooltip을 확인 할수 있다.

 

다음에는 id와 pw를 입력해서 로그인하는 방법 을 작성 하겠습니다.

 // 네이버 로그인 해서 가장 최근 메일 제목 읽어서 가져오기  // TC 1 네이버 창 렌더링 // TC 2 네이버 로그인 // TC 3 최근 메일 TXT 가져오기 // TC 4 네이버 로그아웃  const _url = "https://www.naver.com/"; const webdriver = require('selenium-webdriver'); const {By,Util} = webdriver; require('chromedriver');  var driver = new webdriver.Builder() .forBrowser('chrome') .build(); // 로그인 // ID 입력 document.querySelector("input#id").value="test";  // 패스워드 입력 document.querySelector("input#pw").value="test";  // Login 버튼 클릭 // document.querySelector("input[type='submit']"); // document.querySelector("input[title='로그인']"); // document.querySelector("span.btn_login > input"); // document.querySelector("span.btn_login").children[0];  // 이외에도 셀렉터를 활용한 방법은 너무나도 많다. 단순한 예로 들었을뿐   var loginSelector = [ "input[type='submit']", "input[title='로그인']", "span.btn_login > input" ];  (async () => {     try {         await driver.get(_url);         let loginBtn = await driver.findElement(By.css("input[type='submit']"));         loginBtn.click();         }   finally {             await driver.sleep(2000);             await driver.quit();         } })();   

 

 

 

+ Recent posts