이번 시간에는 Form 요소를 스크립트를 통해 자동화 해보고, UI 요소의 값을 가져와서 정상적으로 Form 양식을 제출했는지 검증까지 해보도록 하겠습니다.

스크립트 작성하기

https://www.selenium.dev/selenium/web/web-form.html 페이지에서 예제 스크립트를 한번 작성해 보도록 하겠습니다.

한번 시나리오를 정의해볼까요? 유저 시나리오가 다음과 같다고 가정합니다.

  1. Text input에 "ABCD"라고 입력합니다
  2. Password에는 "mypassword!"라고 입력합니다
  3. Textarea에는 "Hello\nWorld!"라고 입력합니다
  4. Dropdown(select)에서는 "One" 옵션을 고릅니다
  5. Dropdown(datalist)에는 "Los Angeles"를 고릅니다
  6. File input에는 selenium-web-testing 하위의 click-basic.py 파일을 올립니다
  7. Default radio를 선택합니다
  8. Color 값은 검정색을 고릅니다
  9. Date picker에서는 오늘 날짜를 선택합니다
  10. Range는 1로 선택합니다
  11. 그리고 Submit 버튼을 클릭합니다

이제 VSCode를 실행한 후 selenium-web-testing 폴더를 열고 하위에 ui-manipulation.py 파일을 만들어 줍니다. 그리고 아래와 같이 작성해 줍니다.

from selenium import webdriver

driver = webdriver.Chrome()
driver.get("https://www.selenium.dev/selenium/web/web-form.html")

먼저 첫번째로는 "Text input" 입력칸에 "ABCD" 라고 입력하는 것입니다. 이제 직접 해당 페이지에 들어가 개발자 도구를 열어줍니다.

해당 요소를 선택해 Copy XPath 메뉴를 통해 XPath를 가져옵니다.

복사된 XPath 값은 //*[@id="my-text-id"] 입니다. 요소에 바로 id attribute가 있습니다. 저는 더 자세히 하고 싶기에, 이 XPath를 //input[@id="my-text-id"] 로 변경해서 적어보도록 할게요!

# from selenium import webdriver 다음 라인에 작성합니다.
from selenium.webdriver.common.by import By

# driver.get("https://www.selenium.dev/selenium/web/web-form.html") 다음 라인에 작성합니다
text_input = driver.find_element(By.XPATH, '//input[@id="my-text-id"]')

이제 text_input에 "ABCD" 입력값을 보내야 합니다. Selenium에서 문자열을 해당 요솔로 보내는 방법을 제공하는데요, 한번 살펴보겠습니다. 문서에 의하면, 요소.send_keys("원하는 문자열") 를 통해 보낼 수 있습니다. 모두 지우고 싶다면 요소.clear() 를 통해 입력칸의 문자를 모두 지울 수 있습니다. 한번 작성해 보도록 할게요.

text_input.send_keys("ABCD")

이제 한번 정상적으로 입력을 하는지 테스트해 봅시다.

파이썬 가상환경을 활성화하고 아래와 같은 명령어를 VSCode 터미널에서 입력해주세요.

# 가상환경을 활성화 하지 않았다면 입력해주세요
# for Windows
.venv\Scripts\activate.bat

# for MacOS & Linux
source .venv/bin/activate
python3 ui-manipulation.py

아마 눈에 보이기 전에 모든 작업이 끝나고 브라우저가 닫혔을 텐데요, 코드 진행을 멈추는 트릭(?)을 사용해 보면 위 스크린샷처럼 "ABCD"가 "Text input" 입력칸에 잘 입력되어있는 것을 볼 수 있습니다.

파이썬에서 import time 구문 후 time.sleep(n) 을 통해 n초 동안 멈춰있게 할 수 있습니다.

이후 2번째, 비밀번호 입력을 위해 다시 웹 페이지로 돌아가 개발자 도구를 이용해 해당 요소를 집어봅니다.

이번 요소는 id attribute가 존재하지 않네요. 개발자 도구에서는 shorten XPath는 id attribute를 기준으로 잡아주기 때문에 지금 상황에서는 크게 도움이 되지 않습니다. 그러면 부모 요소들의 id attribute나 현재 요소의 type, class, name, autocomplete attribute들을 가지고 XPath를 만들어 볼 수 있습니다. 여기서 부모 요소들에는 id attribute가 없고, 현재 요소에 고유하게 사용할 것 같은 name 을 가지고 있으므로 이 값을 가지고 XPath를 만들고 "mypassword!" 키를 입력하겠습니다.

password_input = driver.find_element(By.XPATH, '//input[@name="my-password"]')
password_input.send_keys("mypassword!")

다음으로 Dropdown(select)에서 "One" 옵션을 골라보도록 하겠습니다. 개발자 도구로 보면 다음과 같이 보일 것입니다. select 태그 하위에 option 태그가 보입니다.

여기서 option 태그에서 value 값이 1인 요소가 우리가 클릭해야할 요소입니다. 이 요소에 대한 XPath는 //select[@name="my-select"]//option[@value="1"] 로 적을 수 있습니다. name attribute가 "my-select"인 select 요소 하위에 value attribute가 "1"인 option 요소라는 의미입니다. 아래와 같이 코드를 작성해봅니다.

select_option_one = driver.find_element(By.XPATH, '//select[@name="my-select"]//option[@value="1"]')
select_option_one.click()
💡
XPath가 맞는지 확인해보려면 개발자도구 - Console 탭에서 $x("XPATH...") 를 입력해 보세요!

여기서 다시 스크립트를 실행해볼까요?

python3 ui-manipulation.py

입력칸에 값이 모두 들어가고, Dropdown에는 제가 원하는 옵션을 선택하게 되었습니다!👏

다음은 Dropdown(datalist)에는 "Los Angeles"를 골라보도록 하겠습니다. 개발자 도구를 통해 살펴봅시다.

inputdatalist의 조합은 약간 생소하실수 있는데요, 어렵지 않습니다! 이전 input 요소에 문자열을 넣는것과 동일합니다.

datalist_input = driver.find_element(By.XPATH, '//input[@name="my-datalist"]')
datalist_input.send_keys("Los Angeles")

다음은 파일 업로드를 할 차례입니다. 파일은 selenium-web-testing 하위의 click-basic.py 파일을 올려 보도록 하겠습니다. 문서에 따르면 send_keys() 에 파일 경로를 넣어주면 된다고 합니다. click-basic.py 파일 경로를 가져오는 방법은 많지만, 아래 코드를 통해 현재 실행 경로(selenium-web-testing)를 사용해 볼게요.

# from selenium.webdriver.common.by import By 다음 라인에 작성합니다.
import os

file_input = driver.find_element(By.XPATH, "//input[@name='my-file']")
file_input.send_keys(os.getcwd() + "/click-basic.py")

스크립트를 실행해 보면 파일이 올라간 것을 확인해 볼 수 있습니다.

다음은 Default radio를 선택할 차레입니다. 개발자 도구로 먼저 확인해 봅니다.

이 요소를 클릭하는 코드를 작성합니다.

default_radio = driver.find_element(By.XPATH, '//input[@id="my-radio-2"]')
default_radio.click()

다음은 컬러 값을 바꿔보도록 하겠습니다. 개발자 도구로 요소를 확인하고 XPath를 복사하거나 직접 만들어 줍니다. 컬러 선택 또한 send_keys() 를 통해 자동화할 수 있습니다. 검정색은 HEX 코드로 #000000 입니다.

color_input = driver.find_element(By.XPATH, '//input[@name="my-colors"]')
color_input.send_keys("#000000")

날짜 선택은 오늘 날짜로 해보겠습니다. 오늘은 9월 25일인데요, 날짜 선택이 어떻게 이루어지는지 먼저 알아보겠습니다. 개발자 도구를 켜고 Date picker를 선택해 볼게요!

개발자 도구를 켜고 Date picker에 한번 클릭을 하니 div 요소가 생겨나는 것을 볼 수 있습니다. 그리고 UI로는 달력이 보이네요. 여기서 25는 어디에 있는지 개발자 도구에서 찾아봅니다.

이제 스크립트로 Date picker input 요소를 한번 클릭한 다음, 달력에서 텍스트값이 25인 td 요소를 클릭해주면 될 것 같습니다.

calendar_input = driver.find_element(By.XPATH, '//input[@name="my-date"]')
calendar_input.click()
# 변수 할당 없이 클릭도 가능합니다
# td 요소에서 class값이 "day"이고, 텍스트가 25인 요소를 모두 찾습니다
driver.find_element(By.XPATH, '//td[@class="day" and text()="25"]').click()

이제 Range 값을 1로 변경해 보도록 하겠습니다. 개발자 도구로 먼저 살펴봅니다. 현재 값은 5로 되어있고 한 간격당 1(step)씩 증감하므로, 1로 가기까지 4번 왼쪽으로 끌어야 하는 상황입니다.

이런 type="range"의 값을 변경하기 위한 방법으로는 키보드의 왼쪽, 오른쪽 방향키를 눌러보는게 있습니다.

range_input = driver.find_element(By.XPATH, '//input[@name="my-range"]')
# 4번 반복합니다
for i in range(0, 4):
  range_input.send_keys(Keys.LEFT)

마지막으로 Submit 버튼을 누릅니다.

driver.find_element(By.XPATH, '//button[@type="submit"]').click()

이제 모든 시나리오를 다 마쳤습니다!🥳 한번 아래 명령어를 통해 실행해 보도록 하겠습니다.

python3 ui-manipulation.py

마지막 화면은 이렇게 나옵니다! 이제 유저 시나리오를 토대로 스크립트를 통해 웹 UI를 조작할 수 있게 되었습니다. 이런 UI 조작이 입력값이라면, 출력값에 대한 검증을 해야하는데요, Submit 버튼 클릭 후 나오는 UI로 한번 검증해보도록 하겠습니다.

검증하기

마지막 화면에서 "Recieved!" 문구가 나오면 성공했다고 가정해봅시다. 이제 페이지 내 요소의 text값을 가져와 비교를 해볼 텐데요, 실제 스크립트를 작성하기 전 간단하게 작성해 보도록 할게요

SUCCESS_TEXT = "Received!"
result_text = get_text_from_element("'Received!' 텍스트가 있는 요소의 XPath")
# 같은지 비교하기
# SUCCESS_TEXT and result_text are same??

전체적인 흐름은 위와 같을 것입니다. 요소로부터 값을 가져오고 우리는 그 값이 성공했을 때의 값과 같은지 비교하면 될 것 같네요.

값 가져오기

먼저, 요소의 text 값을 가져와야 합니다. 개발자 도구를 켜고 메시지가 어느 요소인지 알아봅시다.

이제 XPath를 알아냈으니 Selenium을 통해 어떻게 텍스트 값을 가져오는지 알아봐야 합니다. 문서에 따르면 .text 를 통해 요소의 텍스트 값에 접근할 수 있습니다.

SUCCESS_TEXT = "Received!"
result_text = driver.find_element(By.XPATH, '//p[@id="message"]').text
# 터미널에 출력합니다
print(result_text)

한번 스크립트를 실행해 result_text 에 값이 잘 담겨있는지 확인해 봅시다!

python3 ui-manipulation.py
> Received!

Assert

파이썬에서는 assert 라는 검증할 수 있는 모듈이 내장되어있습니다. 이번에 assert 를 가지고 두 값을 비교해 보도록 할게요. 만약 SUCCESS_TEXTresult_text 값이 같다면 통과할 것이고, 값이 다르다면 에러를 내서 스크립트가 실패할 것입니다.

먼저 일부러 실패하도록 해보겠습니다

assert SUCCESS_TEXT != result_text

이 때에는 두 값이 달라야 검증이 통과됩니다. 한번 실행해볼까요?

Traceback (most recent call last):
  File "/Users/daniel/Projects/selenium-web-testing/ui-manipulation.py", line 33, in <module>
    assert SUCCESS_TEXT != result_text
AssertionError

위와 같이 AssertionError 가 발생하고 실패합니다. 다음은 제대로 assert를 사용해 봅시다

assert SUCCESS_TEXT == result_text

이제 다시 스크립트를 실행해보면 문제없이 성공했습니다!

Code

# ui-manipulation.py
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import os;

driver = webdriver.Chrome()
driver.get("https://www.selenium.dev/selenium/web/web-form.html")
text_input = driver.find_element(By.XPATH, '//input[@id="my-text-id"]')
text_input.send_keys("ABCD")
password_input = driver.find_element(By.XPATH, '//input[@name="my-password"]')
password_input.send_keys("mypassword!")
select_option_one = driver.find_element(By.XPATH, '//select[@name="my-select"]//option[@value="1"]')
select_option_one.click()
datalist_input = driver.find_element(By.XPATH, '//input[@name="my-datalist"]')
datalist_input.send_keys("Los Angeles")
file_input = driver.find_element(By.XPATH, "//input[@name='my-file']")
file_input.send_keys(os.getcwd() + "/click-basic.py")
default_radio = driver.find_element(By.XPATH, '//input[@id="my-radio-2"]')
default_radio.click()
color_input = driver.find_element(By.XPATH, '//input[@name="my-colors"]')
color_input.send_keys("#000000")
calendar_input = driver.find_element(By.XPATH, '//input[@name="my-date"]')
calendar_input.click()
driver.find_element(By.XPATH, '//td[@class="day" and text()="25"]').click()
range_input = driver.find_element(By.XPATH, '//input[@name="my-range"]')
for i in range(0, 4):
  range_input.send_keys(Keys.ARROW_LEFT)
driver.find_element(By.XPATH, '//button[@type="submit"]').click()

SUCCESS_TEXT = "Received!"
result_text = driver.find_element(By.XPATH, '//p[@id="message"]').text
assert SUCCESS_TEXT == result_text

driver.quit()

마치며

이번에는 Form 예제를 통해 키를 보내고 버튼을 클릭해 제출해 보고, 그 이후 UI에서 텍스트 값을 가져와 assert 로 비교해보았습니다. 다음 글에서는 다른 예제로 스크립트를 작성해보도록 하겠습니다.

예제 코드는 https://github.com/dogu-team/selenium-python-tutorial 에서 확인할 수 있습니다.