ð ãã®èšäºã¯ãããªæ¹ã«ãããã
- Seleniumã䜿ã£ãWebãã©ãŠã¶èªååã«èå³ãããæ¹
- äŒå¡ç»é²ã»ãã©ãŒã å ¥åã®èªååãåŠã³ããQAãšã³ãžãã¢ã»éçºè
- ãã°ã€ã³ã»ãã°ã¢ãŠãã®E2Eãã¹ããå®è£ ãããæ¹
- ã¹ã¯ãªãŒã³ã·ã§ããååŸããã°ç®¡çãèªååãããæ¹
â ãã®èšäºãèªããšåŸãããããš
- Seleniumã§è€æ°ããŒãžã«ããããã©ãŒã æäœãèªååããå®è£ ãã¿ãŒã³ãããã
- XPathã«ããæè»ãªèŠçŽ ç¹å®ã®æžãæ¹ã身ã«ã€ã
- ãã°åºåã»ã¹ã¯ãªãŒã³ã·ã§ãã管çã®å®åçãªå®è£ æ¹æ³ãç¿åŸã§ãã
- ç»é²âãã°ã¢ãŠãâãã°ã€ã³ã®äžé£ã®E2EãããŒãèªåã§çµããããã«ãªã
ðšâð» ãã®èšäºã®ä¿¡é Œæ§ã«ã€ããŠ
æ¬èšäºã¯QAãšã³ãžãã¢ãšããŠå®åã§èªååãã¹ãã«æºããçè
ããå®éã«åäœç¢ºèªæžã¿ã®ã³ãŒããããšã«è§£èª¬ããŠããŸãã
ãœãŒã¹ã³ãŒãã¯ãã¹ãŠ GitHub ã«ãŠå
¬éäžïŒautomated-testing-portfolioïŒã
å®åã§å¹ã£ãããŠããŠãæãã¿ãªãè©°ã蟌ãã§ããŸãã
ãäŒå¡ç»é²ãã©ãŒã ã®ãã¹ããæ¯åæåã§ããã®ã¯ããéçâŠããããªæ©ã¿ãæ±ããããšã¯ãããŸãããïŒ
æ¬èšäºã§ã¯ Python à Selenium ã䜿ã£ãŠããšããã·ã«ã¡ã©ã®äŒå¡ç»é²ãã©ãŒã ãèªåã§å
¥åã»éä¿¡ã»ãã°ã€ã³ç¢ºèªãŸã§è¡ãã¹ã¯ãªããã培åºè§£èª¬ããŸãã
XPathã®è€æ°ãã¿ãŒã³ã«ããå
ç¢ãªèŠçŽ ç¹å®ããã°ãšã¹ã¯ãªãŒã³ã·ã§ããã«ãããããã°ã®ãããããªã©ãå®åã§å³äœ¿ããQAèªååã®èšèšææ³ãäœããšãããªã玹ä»ããŸãã
ð¯ ãã®ãã¹ãã®ç®çïŒãŠãŒã¶ãŒãæ£åžžã«äŒå¡ç»é²ã§ããããE2Eã§æ€èšŒããŸããç»é²å®äºã ãã§ãªãããã®åŸã®ãã°ã€ã³ã»ãã°ã¢ãŠããŸã§äžæ°é貫ã§ä¿èšŒããŸãã
- ãã¹ã芳ç¹
- ãã®ã¹ã¯ãªããã§ã§ããããš
- èªååãããŒå šäœå
- ãœãŒã¹ã³ãŒãå šæ
- äž»èŠã¡ãœãã解説
- â __init__() â ã¯ã©ã¹ã®åæåã»ChromeDriverã®èšå®
- â¡ log() / take_screenshot() â ãã°ç®¡çãšãšããã³ã¹åé
- ⢠fill_basic_info() â æ°åã»ããªã¬ãã®èªåå ¥å
- ⣠fill_address() â éµäŸ¿çªå·æ€çŽ¢ïŒäœæå ¥å
- †fill_contact_info() â é»è©±çªå·ã»çå¹Žææ¥ã»ã¡ãŒã«ã¢ãã¬ã¹ã®å ¥å
- ⥠accept_terms() â å©çšèŠçŽãã§ãã¯ããã¯ã¹
- ⊠click_next_button() / click_confirm_button() â ç»é¢é·ç§»ãã¿ã³ã®ã¯ãªãã¯
- â§ login() / logout() â ãã°ã€ã³ç¢ºèªãšåŸåŠç
- âš reset_password() â ãã¹ã¯ãŒããªã»ãããããŒ
- å®è¡ãã°ã®ãµã³ãã«
- ããã«çºå±ãããããã®æ¹åã¢ã€ãã¢
- 掻çšã·ãŒã³ã»æ¡åŒµäŸ
- å®åãžã®å¿çšïŒPOMèšèš à CI/CD飿º
- ããããã€ã³ã
- â ãã§ãã¯ããã¯ã¹ãéåžžã¯ãªãã¯ã§åå¿ããªã
- â¡ ãã«ããŠã³ïŒselectã¿ã°ïŒãçŽæ¥ã¯ãªãã¯ã§éžæã§ããªã
- ⢠ãã¿ã³ã®XPathã1ãã¿ãŒã³ã ãšå£ãããã
- ⣠éµäŸ¿çªå·ãã£ãŒã«ãã®ç¹å®ã«æéåã£ã
- †ãã°ã€ã³æåŠã®å€å®ãé£ããã£ã
- ãŸãšã
ãã¹ã芳ç¹
æ¬ã¹ã¯ãªããã¯ä»¥äžã®ãã¹ã芳ç¹ãã«ããŒããŠããŸããQAãšã³ãžãã¢ãšããŠãäœãä¿èšŒãããã¹ããããæç¢ºã«ããŠããããšãå®åã§ã¯éèŠã§ãã
| èŠ³ç¹ | å 容 | æ¬ã¹ã¯ãªããã§ã®å¯Ÿå¿ |
|---|---|---|
| â æ£åžžç³» | ç»é²æåã»ãã°ã€ã³æå | ç»é²âãã°ã¢ãŠãâãã°ã€ã³ãäžæ°éè²«ã§æ€èšŒ |
| â ïž æªå ¥åãšã©ãŒ | å¿ é é ç®ãæªå ¥åã®å Žåã®ãšã©ãŒè¡šç€ºç¢ºèª | åã¹ããã倱ææã«ãã°åºåïŒã¹ã¯ãªãŒã³ã·ã§ããä¿å |
| â ïž äžæ£ã¡ãŒã«åœ¢åŒ | ã@ãªããããã¡ã€ã³ãªãããªã©äžæ£ãªåœ¢åŒã§ã®å ¥å | ãã¹ãããŒã¿ãå·®ãæ¿ããŠç°åžžç³»ãã¿ãŒã³ãæ€èšŒå¯èœ |
| â ïž PWæ¡ä»¶éå | æåæ°äžè¶³ã»äœ¿çšäžå¯æåãªã©æ¡ä»¶ãæºãããªãPW | fill_password() ã®ãã©ã¡ãŒã¿ãå€ããŠç¢ºèªå¯èœ |
| ð éè€ç»é² | åäžã¡ãŒã«ã¢ãã¬ã¹ã§2åç®ã®ç»é²ã詊ã¿ãéã®æå | åã email ã䜿ã£ãŠåå®è¡ããããšã§ç¢ºèªå¯èœ |
ãã®ã¹ã¯ãªããã§ã§ããããš
1ã€ã®ã¯ã©ã¹ã«ç»é²ããã°ã¢ãŠãããã°ã€ã³ãŸã§å®çµããããã«èªååãããŒãå®è£ ããŠããŸãã
ð
ãã©ãŒã èªåå ¥å
æ°åã»ããªã¬ãã»äœæã»é»è©±çªå·ã»çå¹Žææ¥ã»ã¡ãŒã«ã¢ãã¬ã¹ãèªåã§å ¥å
ð®
éµäŸ¿çªå·âäœææ€çŽ¢
éµäŸ¿çªå·å ¥ååŸã«ãäœæãæ€çŽ¢ããããã¿ã³ãã¯ãªãã¯ããäœæåè£ããéžæ
â
èŠçŽåæãã§ãã¯ããã¯ã¹
ãã§ãã¯ããã¯ã¹ãžã®ã¯ãªãã¯ã»ç¶æ 確èªã»JSçµç±ã®ãã©ãŒã«ããã¯å¯Ÿå¿
ð
ãã¹ã¯ãŒãå ¥åïŒç¢ºèªç»é¢ïŒ
確èªç»é¢ã§ãã¹ã¯ãŒããšç¢ºèªçšãã¹ã¯ãŒããèªåå ¥å
ðž
ã¹ã¯ãªãŒã³ã·ã§ããèªåä¿å
åã¹ãããã§èªåçã«PNGä¿åããããã°æã«èŠèŠçã«ç¢ºèªã§ãã
ð
ãã°ãã¡ã€ã«åºå
ã¿ã€ã ã¹ã¿ã³ãä»ãã®ãã°ãããã¹ããã¡ã€ã«ã«ä¿åãå®è¡å±¥æŽã远跡å¯èœ
èªååãããŒå šäœå
signup_complete() ã¡ãœãããå
šã¹ããããçµ±æ¬ããŸããåã¹ããããç¬ç«ããã¡ãœããã«åé¢ãããŠããããããããã°ãåå©çšã容æã§ãã
| Step | åŠçå 容 | åŒã³åºãã¡ãœãã | ã¹ã¯ãªãŒã³ã·ã§ãã |
|---|---|---|---|
| 1 | ãããããŒãžâäŒå¡ç»é²ããŒãžãžé·ç§» | navigate_to_register_page() |
01_registration_page.png |
| 2 | æ°åã»ããªã¬ãå ¥å | fill_basic_info() |
â |
| 3 | éµäŸ¿çªå·ã»äœæå ¥å | fill_address() |
â |
| 4 | é»è©±çªå·ã»çå¹Žææ¥ã»ã¡ãŒã«å ¥å | fill_contact_info() |
â |
| 5 | å©çšèŠçŽãžã®åæãã§ã㯠| accept_terms() |
02_form_filled.png |
| 6 | ãæ¬¡ãžé²ãããã¿ã³ã¯ãªã㯠| click_next_button() |
03_confirmation_page.png |
| 7 | 確èªç»é¢ã§ãã¹ã¯ãŒãå ¥å | fill_password() |
04_password_filled.png |
| 8 | ãç»é²ããããã¿ã³ã¯ãªã㯠| click_confirm_button() |
05_registration_complete.png |
| 9 | ãã°ã¢ãŠã | logout() |
06_after_logout.png |
| 10 | ç»é²ã¢ã«ãŠã³ãã§ãã°ã€ã³ç¢ºèª | login() |
07_after_login.png |
| 11 | 2åç®ã®ãã°ã¢ãŠã | logout() |
08_after_second_logout.png |
å®éã«ã¹ã¯ãªãããå®è¡ãããšãæ°åã»ããªã¬ãã»äœæã»é»è©±çªå·ã»çå¹Žææ¥ã»ã¡ãŒã«ã¢ãã¬ã¹ããã¹ãŠèªåã§å ¥åãããŸãããã¹ãããŒã¿ã¯èŸæžåœ¢åŒã§ç®¡çããŠãããããå¥ã®ããŒã¿ã«å·®ãæ¿ããã®ãç°¡åã§ãã
â² Seleniumãèªåå ¥åããäŒå¡ç»é²ãã©ãŒã ãå±±ç°å€ªéã®ãã¹ãããŒã¿ãå šé ç®ã«æ£ç¢ºã«å ¥åãããŠãã
ãœãŒã¹ã³ãŒãå šæ
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select
from datetime import datetime
import os
import time
class YodobashiAutoSignup:
def __init__(self, headless=False):
self.top_url = "https://www.yodobashi.com/"
self.register_url = "https://order.yodobashi.com/yc/member/register/index.html"
options = webdriver.ChromeOptions()
options.add_argument('--disable-blink-features=AutomationControlled')
if not headless:
options.add_argument('--start-maximized')
else:
options.add_argument('--headless')
options.add_argument('--disable-popup-blocking')
self.driver = webdriver.Chrome(options=options)
self.wait = WebDriverWait(self.driver, 15)
self.log_folder = os.path.join(
os.path.expanduser("~"), "Desktop", "yodobashi_signup_logs"
)
self.setup_log_folder()
self.log_file = os.path.join(
self.log_folder,
f"signup_log_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
)
def setup_log_folder(self):
if not os.path.exists(self.log_folder):
os.makedirs(self.log_folder)
def log(self, message):
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
log_message = f"[{timestamp}] {message}"
print(log_message)
with open(self.log_file, 'a', encoding='utf-8') as f:
f.write(log_message + '\n')
def take_screenshot(self, name):
screenshot_name = name.replace('(', '_').replace(')', '').replace(' ', '_')
screenshot_path = os.path.join(
self.log_folder,
f"screenshot_{screenshot_name}_{datetime.now().strftime('%H%M%S')}.png"
)
self.driver.save_screenshot(screenshot_path)
self.log(f" ð· Screenshot: {os.path.basename(screenshot_path)}")
return screenshot_path
# ---- 以éãfill_basic_info / fill_address / fill_contact_info /
# fill_password / accept_terms / click_next_button /
# click_confirm_button / navigate_to_register_page /
# signup_complete / login / logout / reset_password /
# close ãªã©ãå®è£
----
# å®è¡ãµã³ãã«
if __name__ == "__main__":
user_data = {
"last_name": "å±±ç°",
"first_name": "倪é",
"last_kana": "ã€ãã",
"first_kana": "ã¿ããŠ",
"postal_code": "1500001",
"address_detail": "1-1-1",
"building": "ãµã³ãã«ãã«101",
"phone": "09012345678",
"birth_year": "1990",
"birth_month": "1",
"birth_day": "1",
"email": "test822211@example.com"
}
bot = YodobashiAutoSignup(headless=False)
try:
result = bot.signup_complete(user_data, password="hjerty12")
print(f"Result: {result['message']}")
finally:
bot.close()
äž»èŠã¡ãœãã解説
ã¯ã©ã¹ã¯å šéšã§10以äžã®ã¡ãœããã§æ§æãããŠããŸãããããããç¬ç«ãã責åãæã¡ãåäœã§ã®ãããã°ã»åå©çšã»æ¡åŒµãããããèšèšã«ãªã£ãŠããŸãã以äžã§ç¹ã«éèŠãªã¡ãœããã詳ãã解説ããŸãã
â __init__() â ã¯ã©ã¹ã®åæåã»ChromeDriverã®èšå®
ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹çææã«åŒã°ããåæåã¡ãœããã§ããChromeDriverã®ãªãã·ã§ã³èšå®ããã°ãã©ã«ãã®äœæãWebDriverWaitã®æºåãªã©ãããã§è¡ããŸããåŒæ° headless=False ã True ã«å€ããã ãã§ãã©ãŠã¶ãé衚瀺ã«ããŠå®è¡ã§ãããããCI/CDç°å¢ã§ã®å®è¡ã«ã察å¿ããŠããŸãã
ð ãã€ã³ãïŒ--disable-blink-features=AutomationControlled ãªãã·ã§ã³ã远å ããããšã§ãSeleniumã«ããèªåæäœããµã€ãåŽã«æ€ç¥ããã«ããããŠããŸããããã¯Bot察çãæœããããµã€ãã§ã®ãã¹ãã«æå¹ãªãã¯ããã¯ã§ãã
â æ³šæïŒãã°ãã¡ã€ã«ãšã¹ã¯ãªãŒã³ã·ã§ããã¯ãã¹ã¯ãããã® yodobashi_signup_logs ãã©ã«ãã«èªåä¿åãããŸããå®è¡ã®ãã³ã«ã¿ã€ã ã¹ã¿ã³ãä»ãã®æ°èŠãã¡ã€ã«ãäœæããããããå®è¡å±¥æŽãäžæžããããããšã¯ãããŸããã
â¡ log() / take_screenshot() â ãã°ç®¡çãšãšããã³ã¹åé
log() ã¯ã¿ã€ã ã¹ã¿ã³ãä»ãã®ã¡ãã»ãŒãžãã³ã³ãœãŒã«ãšããã¹ããã¡ã€ã«ã®äž¡æ¹ã«åæåºåããŸããtake_screenshot() ã¯ä»»æã®ã¿ã€ãã³ã°ã§ç»é¢ãã£ããã£ãPNGä¿åããä»çµã¿ã§ãããã®2ã€ã®ã¡ãœãããå
šã¹ãããã«æ¿å
¥ãããŠããããããã¹ã倱ææã«ãã©ã®ã¹ãããã§ã»äœãèµ·ãããããç»åãšæåãã°ã§è¿œè·¡ã§ããŸãã
ð¡ å®åTipïŒQAã®çŸå Žã§ã¯ããã¹ããšããã³ã¹ïŒèšŒè·¡ïŒãã®æåºãæ±ããããããšãå€ãã§ããã¹ã¯ãªãŒã³ã·ã§ãããèªååéããŠããããšã§ããã¹ãå ±åæžã®äœæå·¥æ°ãå€§å¹ ã«åæžã§ããŸããallure-pytestãšçµã¿åããããšãã¹ã¯ã·ã§ä»ãã®HTMLã¬ããŒããèªåçæããããšãå¯èœã§ãã
⢠fill_basic_info() â æ°åã»ããªã¬ãã®èªåå ¥å
å
š input[type="text"] ãäžæ¬ååŸããplaceholder 屿§ãš name 屿§ã®æååã§ãã£ãŒã«ããç¹å®ããŸããåçŽã«ãæåã®inputã«å
¥åããããšããå®è£
ã§ã¯ãªãã屿§å€ãèŠãŠå€æããã¢ãããŒããåãããšã§ããã©ãŒã ã®é çªãå€ãã£ãŠãå£ãã«ãããªã£ãŠããŸãã
â ãã€ã³ãïŒkana ç³»ã®ãã£ãŒã«ãã誀ã£ãŠæŒ¢åãã£ãŒã«ãã«æ··å
¥ãããªãããã'kana' not in name_attr.lower() ã®æ¡ä»¶ã§æç€ºçã«é€å€ããŠããŸãã
⣠fill_address() â éµäŸ¿çªå·æ€çŽ¢ïŒäœæå ¥å
äœæå ¥åã¯åçŽãªæåå ¥åã§ã¯ãªããéµäŸ¿çªå·æ€çŽ¢âåè£éžæâçªå°å ¥åãšããè€æ°ã¹ãããã絡ãåŠçã§ãã7æ¡ã®éµäŸ¿çªå·ãå3æ¡ã»åŸ4æ¡ã«åå²ããŠ2ã€ã®inputã«å ¥ååŸããäœæãæ€çŽ¢ããããã¿ã³ãXPathã§æ€çŽ¢ããŠã¯ãªãã¯ããŸãã
postal = user_data['postal_code'] # äŸ: '1500001'
postal1 = postal[:3] # '150'
postal2 = postal[3:] # '0001'
# name屿§ã« 'zip' ãŸã㯠'postal' ãå«ãinputãæœåº
postal_inputs = []
for inp in self.driver.find_elements(By.XPATH, "//input[@type='text']"):
name_attr = inp.get_attribute('name') or ''
if 'zip' in name_attr.lower() or 'postal' in name_attr.lower():
postal_inputs.append(inp)
ð èšèšãã€ã³ãïŒéµäŸ¿çªå·ãã£ãŒã«ããid/nameã§ã¯ãªããzipã»postalãšããæååãå«ãããšããæ¡ä»¶ã§æ¢ããŠããã®ã¯ããµã€ããªãã¥ãŒã¢ã«ã«ããid倿Žã«å¯Ÿå¿ããããã§ããå®å šäžèŽããéšåäžèŽã®æ¹ã倿Žã«åŒ·ããšããå®åçãªèãæ¹ã§ãã
†fill_contact_info() â é»è©±çªå·ã»çå¹Žææ¥ã»ã¡ãŒã«ã¢ãã¬ã¹ã®å ¥å
é»è©±çªå·ã¯11æ¡ãš10æ¡ã®äž¡ãã¿ãŒã³ã«å¯Ÿå¿ãã3åå²ããŠå
¥åããŸããçå¹Žææ¥ã®ãæããæ¥ã㯠<select> ã¿ã°ã®ãã«ããŠã³ã«ãªã£ãŠãããããSelect ã¯ã©ã¹ã䜿ã£ãŠ select_by_value() ã§éžæããŸãã
ð¡ TipïŒãã«ããŠã³ïŒselectã¿ã°ïŒã®æäœã«ã¯å¿
ã from selenium.webdriver.support.ui import Select ãã€ã³ããŒãã㊠Select(element) ã§ã©ããããå¿
èŠããããŸããçŽæ¥ click() ããŠããªãã·ã§ã³ãéžæã§ããªãã®ã§æ³šæããŸãããã
⥠accept_terms() â å©çšèŠçŽãã§ãã¯ããã¯ã¹
id="js_i_checkPrivacyPolicyAgreement" ã§çŽæ¥ååŸããéåžžã¯ãªã㯠â JSã¯ãªã㯠â JSã§çŽæ¥ããããã£å€æŽã®3段æ§ãã§ç¢ºå®ã«ãã§ãã¯ãå
¥ããŸããã¯ãªãã¯åŸã« is_selected() ã§ç¶æ
ãå確èªããã®ãå
ç¢ãã®ãã€ã³ãã§ãã
ð¡ TipïŒãã§ãã¯ããã¯ã¹ã¯ visibility:hidden ã§ã©ãã«ãã¯ãªãã¯ãããå®è£
ãå€ããããJSãã©ãŒã«ããã¯ã¯ã»ãŒå¿
é ã§ããarguments[0].click()ïŒã¯ãªãã¯ã€ãã³ãçºç«ïŒãš arguments[0].checked = trueïŒããããã£çŽæ¥å€æŽïŒã¯å¥ç©ãªã®ã§äž¡æ¹æã£ãŠãããŸãããã
⊠click_next_button() / click_confirm_button() â ç»é¢é·ç§»ãã¿ã³ã®ã¯ãªãã¯
ãæ¬¡ãžé²ããããã®å 容ã§ç»é²ããããç»é²ããããªã©ããã¿ã³ã®ããã¹ããè€æ°ãã¿ãŒã³èãããããããXPathã»ã¬ã¯ã¿ãé åã§æã¡ãäžããé ã«è©Šè¡ããæ¹åŒãæ¡çšããŠããŸãããŸãããæ»ããããã£ã³ã»ã«ããå«ãèŠçŽ ã¯é€å€æ¡ä»¶ã§ç¢ºå®ã«åŒŸããŠããŸãã
â èšèšã®ãã€ã³ãïŒè€æ°ã®ã»ã¬ã¯ã¿ãåªå é äœä»ãã§è©Šè¡ãããã©ãŒã«ããã¯èšèšã¯ãå®åã®Seleniumãã¹ãã§ãã²åãå ¥ãããææ³ã§ãã
â§ login() / logout() â ãã°ã€ã³ç¢ºèªãšåŸåŠç
ç»é²å®äºåŸã«ãã®ãŸãŸãã°ã¢ãŠãâãã°ã€ã³ãå®è¡ããããšã§ãç»é²å®äºã ãã§ãªããã°ã€ã³å¯èœç¶æ
ãŸã§äžæ°é貫ã§ç¢ºèªã§ããŸãããã°ã€ã³æåŠã®æ€èšŒã¯ body.text ã«ãããã«ã¡ã¯ããããããå«ãŸãããã§å€å®ããŠããŸãã
| ã¡ãœãã | èŠçŽ ç¹å®ã®å·¥å€« | æåå€å®ããžã㯠|
|---|---|---|
login() |
è€æ°ã»ã¬ã¯ã¿ãé çªã«è©Šè¡ãlogoutå«ãhrefã¯é€å€ | bodyå ã«ãããã«ã¡ã¯ããããããå«ãŸããã |
logout() |
ãŠãŒã¶ãŒåãªã³ã¯ã®ã¯ãªãã¯ã§ããããããŠã³ãéãããã°ã¢ãŠããèŠçŽ ãæ€çŽ¢ | ãã°ã¢ãŠãèŠçŽ ãèŠã€ãããªãå Žåã¯ãæ¢ã«ãã°ã¢ãŠãæžã¿ããšããŠTrueãè¿ã |
âš reset_password() â ãã¹ã¯ãŒããªã»ãããããŒ
ããã¹ã¯ãŒããå¿ããæ¹ã¯ãã¡ãããªã³ã¯ããå§ãŸããã¹ã¯ãŒããªã»ãããããŒãèªååããŸããã¡ãŒã«ã¢ãã¬ã¹ã»å§ã»åãå ¥åããŠéä¿¡ãã¿ã³ãæŒããŸã§ã®æäœãèªåã§è¡ããŸãã
ð ãã€ã³ãïŒãªã»ãããããŒéå§åã« logout() ãåŒã³åºããŠãã°ã¢ãŠãç¶æ
ã確ä¿ããŠããŸãããã°ã¢ãŠãã倱æããŠãåŠçãç¶ç¶ããèšèšã«ãããåã®ã¹ãããã®ç¶æ
ã«äŸåããªãå
ç¢ãªãã¹ããããŒãå®çŸããŠããŸãã
å®è¡ãã°ã®ãµã³ãã«
å®è¡ãããšã³ã³ãœãŒã«ãšããã¹ããã¡ã€ã«ã«ä»¥äžã®ãããªãã°ãåºåãããŸããåã¹ãããã®å®è¡ç¶æ³ããªã¢ã«ã¿ã€ã ã§ç¢ºèªã§ããŸãã
[2025-07-10 14:32:01] ======================================================================
[2025-07-10 14:32:01] Yodobashi Camera Member Registration Automation (Full Flow)
[2025-07-10 14:32:01] Password: hjerty12
[2025-07-10 14:32:02] [Step 1] Navigating to member registration page...
[2025-07-10 14:32:05] â Registration link clicked
[2025-07-10 14:32:08] ð· Screenshot: screenshot_01_registration_page_143208.png
[2025-07-10 14:32:08] [Step 2] Filling in basic information...
[2025-07-10 14:32:09] â Last name: å±±ç°
[2025-07-10 14:32:09] â First name: 倪é
[2025-07-10 14:32:10] â Last name (Kana): ã€ãã
[2025-07-10 14:32:10] â First name (Kana): ã¿ããŠ
[2025-07-10 14:32:11] [Step 3] Filling in address information...
[2025-07-10 14:32:12] â Postal code: 150-0001
[2025-07-10 14:32:14] â Address search executed
[2025-07-10 14:32:15] â Street address: 1-1-1
[2025-07-10 14:32:16] [Step 5] Agreeing to terms...
[2025-07-10 14:32:18] â Agreed to terms (normal click)
[2025-07-10 14:32:18] ð· Screenshot: screenshot_02_form_filled_143218.png
[2025-07-10 14:32:19] [Step 6] Proceeding to confirmation screen...
[2025-07-10 14:32:22] â Click successful
[2025-07-10 14:32:32] â Member registration complete!
[2025-07-10 14:32:45] â Login successful!
[2025-07-10 14:32:50] Final result: Registration, logout, login, and logout all completed!
â ïž ãããªãšã©ãŒãåºãå Žåã¯ïŒ
======================================================================
çµæ: ãã¹ã¯ãŒãå
¥åã«å€±æããŸãã
Email: test****@example.com
Password: ******
ãã°ãã¡ã€ã«: C:\Users\HP\Desktop\yodobashi_signup_logs\signup_log_****.txt
======================================================================
ãã®ãšã©ãŒãåºãåå ãšããŠæãå€ãã®ãããã§ã«ç»é²æžã¿ã®ã¡ãŒã«ã¢ãã¬ã¹ã䜿ã£ãŠããã±ãŒã¹ã§ãã
emailã®å€ãå¥ã®ã¢ãã¬ã¹ïŒäŸïŒtest_99999@example.comïŒã«å€æŽããŠåå®è¡ããŠãã ãã- ãã¹ãçšã«è€æ°ã®ã¡ãŒã«ã¢ãã¬ã¹ãã¿ãŒã³ãçšæããŠãããšäŸ¿å©ã§ã
- åãã¢ãã¬ã¹ã§åç»é²ããããšãããšãéè€ç»é²ãšã©ãŒããšãªãããã¹ã¯ãŒãå ¥åã¹ããããŸã§é²ããŸãã
ãã¡ããå®éã«çè ã®ç°å¢ã§å®è¡ãããšãã®ã¿ãŒããã«åºåã§ããã¹ããã1ã3ãé çªã«å®è¡ãããåå ¥åé ç®ãâã§ç¢ºèªãããŠããã®ãããããŸãã
â² å®éã®ã¿ãŒããã«åºåãã¹ããã1ïŒããŒãžé·ç§»ïŒâã¹ããã2ïŒåºæ¬æ å ±å ¥åïŒâã¹ããã3ïŒäœæå ¥åïŒãšé çªã«å®è¡ããã
ããã«çºå±ãããããã®æ¹åã¢ã€ãã¢
ð ããŒã¿é§åãã¹ãïŒDDTïŒ
user_data ãCSVãExcelããèªã¿èŸŒã圢åŒã«ããããšã§ãè€æ°ãŠãŒã¶ãŒã§ã®äžæ¬ãã¹ããå¯èœã«ãªããŸããpandas.read_csv() ãšçµã¿åããããšå¹æçã§ãã
⡠䞊åå®è¡ã§é«éå
concurrent.futures.ThreadPoolExecutor ã pytest-xdist ã䜿ã£ã䞊åå®è¡ã§ãè€æ°ã¢ã«ãŠã³ãã®ç»é²ç¢ºèªãåæã«è¡ããŸãã
ð¡ïž ãªãã©ã€æ©èœã®åŒ·å
ãããã¯ãŒã¯é
å»¶ãåçã³ã³ãã³ãã«ããäžå®å®ããžã®å¯ŸçãšããŠãtenacity ã©ã€ãã©ãªã䜿ã£ãèªåãªãã©ã€æ©æ§ã远å ãããšããå
ç¢ã«ãªããŸãã
ð HTMLã¬ããŒãåºå
pytest + allure-pytest ãçµã¿åãããããšã§ãã¹ã¯ãªãŒã³ã·ã§ããä»ãã®çŸéºãªHTMLãã¹ãã¬ããŒããèªåçæã§ããŸãã
掻çšã·ãŒã³ã»æ¡åŒµäŸ
ð ãã®ã³ãŒããæŽ»ããå Žé¢
𧪠ãªã°ã¬ãã·ã§ã³ãã¹ã
ãªãªãŒã¹åã«äŒå¡ç»é²ãããŒãå£ããŠããªãããèªåã§ç¢ºèªãCI/CDïŒGitHub ActionsçïŒã«çµã¿èŸŒãã°æ¯ãããã€åŸã«èªåå®è¡ã§ããŸãã
ð åãå ¥ããã¹ãèªåå
ã¹ããŒã¯ãã«ããŒãžã®å ±åçšã«ã¹ã¯ãªãŒã³ã·ã§ããä»ãã®ãšããã³ã¹ãèªååéããã¹ããšããã³ã¹äœæã®å·¥æ°ãå€§å¹ åæžã§ããŸãã
ð§ E2Eãã¹ãã®åŠç¿çŽ æ
Seleniumã®èŠçŽ ç¹å®ã»åŸ æ©åŠçã»ã¹ã¯ãªãŒã³ã·ã§ããã»ãã°åºåãªã©ãå®åçãªãã¿ãŒã³ãäžéãè©°ãŸã£ãåŠç¿ææãšããŠæé©ã§ãã
ð ãã¹ã¯ãŒããªã»ãããããŒç¢ºèª
reset_password() ã¡ãœããã§ããã¹ã¯ãŒããå¿ããæ¹ã¯ãã¡ãããããŒã®åäœç¢ºèªãèªååããã°ã€ã³ç³»ã®å
šã·ããªãªãã«ããŒã§ããŸãã
å®åãžã®å¿çšïŒPOMèšèš à CI/CD飿º
ð Page Object ModelïŒPOMïŒ
å®åã§ã¯Page Object ModelïŒPOMïŒã䜿ã£ãŠãã¹ãã³ãŒããåé¢ããããšã§ãä¿å®æ§ãé«ããŸããããŒãžããšã«ã¯ã©ã¹ãåããæäœããžãã¯ãšãã¹ãããžãã¯ãåãé¢ãã®ãSeleniumã®å®çªèšèšã§ãã
pages/register_page.py â æäœããžãã¯
tests/test_register.py â ãã¹ãã±ãŒã¹âïž CI/CD ãžã®çµã¿èŸŒã¿
ãã®ãã¹ãã¯CI/CDã«çµã¿èŸŒãããšã§èªåå®è¡ãå¯èœã§ããGitHub Actionsãšçµã¿åãããã°ããããã€ã®ãã³ã«äŒå¡ç»é²ãããŒã®å質ãèªåä¿èšŒã§ããŸãã
push â GitHub Actionsèµ·å
â pytestå®è¡ â ã¬ããŒãçæããããã€ã³ã
å®è£ äžã«å®éã«ã€ãŸãããç®æããŸãšããŸãããåããšããã§ãããæ¹ã®åèã«ãªãã°å¬ããã§ãã
â ãã§ãã¯ããã¯ã¹ãéåžžã¯ãªãã¯ã§åå¿ããªã
å©çšèŠçŽã®ãã§ãã¯ããã¯ã¹ã« click() ãå®è¡ããŠãããã§ãã¯ãå
¥ããªãã±ãŒã¹ãçºçããŸãããåå ã¯ãã§ãã¯ããã¯ã¹æ¬äœã visibility:hidden ã§é ãããŠãããå®éã¯ã©ãã«èŠçŽ ãã¯ãªãã¯ãããå®è£
ã«ãªã£ãŠããããã§ãã
# â éåžžã¯ãªãã¯ã§ã¯åå¿ããªãããšããã
checkbox = driver.find_element(By.ID, "js_i_checkPrivacyPolicyAgreement")
checkbox.click()
# â
JSã¯ãªã㯠â ããããã£çŽæ¥å€æŽã®3段æ§ãã§è§£æ±º
try:
checkbox.click()
except:
driver.execute_script("arguments[0].click();", checkbox)
if not checkbox.is_selected():
driver.execute_script("arguments[0].checked = true;", checkbox)
ð¡ ãã€ã³ãïŒ arguments[0].click()ïŒã¯ãªãã¯ã€ãã³ãçºç«ïŒãš arguments[0].checked = trueïŒããããã£çŽæ¥å€æŽïŒã¯å¥ç©ã§ããäž¡æ¹æã£ãŠãããšã»ãŒå
šãŠã®ã±ãŒã¹ã«å¯Ÿå¿ã§ããŸãã
â¡ ãã«ããŠã³ïŒselectã¿ã°ïŒãçŽæ¥ã¯ãªãã¯ã§éžæã§ããªã
çå¹Žææ¥ã®ãæããæ¥ãããã«ããŠã³ã«ãªã£ãŠãããããéåžžã® click() ã§ã¯éžæã§ããŸããã§ãããSelect ã¯ã©ã¹ã䜿ããªããšå€ãéžæã§ããªãããšãç¥ããã«ããããŸããã
# â çŽæ¥ã¯ãªãã¯ããŠãéžæã§ããªã
month_element.click()
# â
Selectã¯ã©ã¹ã§ã©ããããŠæäœ
from selenium.webdriver.support.ui import Select
select = Select(month_element)
select.select_by_value("1") # 1æãéžæ
ð¡ ãã€ã³ãïŒ <select> ã¿ã°ã®æäœã«ã¯å¿
ã Select ã¯ã©ã¹ã䜿ããŸããã€ã³ããŒããå¿ããã«ã
⢠ãã¿ã³ã®XPathã1ãã¿ãŒã³ã ãšå£ãããã
ãæ¬¡ãžé²ãããã¿ã³ãXPath1ãã¿ãŒã³ã§æå®ããŠãããšããããµã€ãã®åŸ®åŠãªå€æŽã§ãã¿ã³ãèŠã€ãããªããªããŸããããã¿ã³ã®ããã¹ãã¯ã次ãžããæ¬¡ãžé²ãããé²ãããªã©è€æ°ãã¿ãŒã³ååšããããšãå€ãããã1ã€ã ãã§ã¯äžååã§ããã
# â 1ãã¿ãŒã³ã ãã ãšå£ãããã
button = driver.find_element(By.XPATH, "//button[text()='次ãžé²ã']")
# â
è€æ°ãã¿ãŒã³ãé çªã«è©Šããã©ãŒã«ããã¯èšèš
selectors = [
"//button[contains(text(),'次ãž')]",
"//input[@type='submit']",
"//a[contains(text(),'次ãž')]",
]
for selector in selectors:
elements = driver.find_elements(By.XPATH, selector)
if elements:
elements[0].click()
break
ð¡ ãã€ã³ãïŒ è€æ°ã®ã»ã¬ã¯ã¿ãåªå é äœä»ãã§è©Šè¡ãããã©ãŒã«ããã¯èšèšã¯ãå®åã®Seleniumãã¹ãã§ãã²åãå ¥ãããææ³ã§ãã
⣠éµäŸ¿çªå·ãã£ãŒã«ãã®ç¹å®ã«æéåã£ã
éµäŸ¿çªå·ãã£ãŒã«ãã id ã§çŽæ¥æå®ããŠãããšããããµã€ããªãã¥ãŒã¢ã«ã§ id ãå€ãã£ãŠãã¹ããå£ããŸãããå®å
šäžèŽããéšåäžèŽã®æ¹ã倿Žã«åŒ·ãããšãåŠã³ãŸããã
# â idã®å®å
šäžèŽã¯å€æŽã«åŒ±ã
driver.find_element(By.ID, "zipCode1")
# â
name屿§ã®éšåäžèŽã§æè»ã«å¯Ÿå¿
for inp in driver.find_elements(By.XPATH, "//input[@type='text']"):
name_attr = inp.get_attribute('name') or ''
if 'zip' in name_attr.lower() or 'postal' in name_attr.lower():
postal_inputs.append(inp)
ð¡ ãã€ã³ãïŒ IDãã¯ã©ã¹åã®å®å šäžèŽããã屿§å€ã®éšåäžèŽã§æ¢ãæ¹ããµã€ã倿Žã«åŒ·ããã¡ã³ããã³ã¹ã³ã¹ããäžãããŸãã
†ãã°ã€ã³æåŠã®å€å®ãé£ããã£ã
ãã°ã€ã³åŸã«ãæåãããã©ããããå€å®ããæ¹æ³ã§æ©ã¿ãŸãããURLãå€ãããªãã±ãŒã¹ããããããŒãžã¿ã€ãã«ãURLã ãã§ã¯å€å®ã§ããªãå Žé¢ããããŸããã
# â URLã ãã§ã¯å€å®ã§ããªãããšããã
if "mypage" in driver.current_url:
print("ãã°ã€ã³æå")
# â
ããŒãžæ¬æã«å«ãŸããããã¹ãã§å€å®
body_text = driver.find_element(By.TAG_NAME, "body").text
if "ããã«ã¡ã¯" in body_text or "ãã" in body_text:
print("ãã°ã€ã³æå")
â ïž æ³šæïŒ å€å®ã«äœ¿ãããã¹ãã¯ãµã€ãã«ãã£ãŠç°ãªããŸããå®éã«ãã°ã€ã³åŸã®ããŒãžã確èªããŠã確å®ã«è¡šç€ºãããããã¹ããéžã³ãŸãããã
ãŸãšã
æ¬èšäºã§ã¯ããšããã·ã«ã¡ã©ã®äŒå¡ç»é²ãã©ãŒã ã Python à Selenium ã§èªååããã¹ã¯ãªããã解説ããŸããã
ã¹ã¯ãªããå®è¡åŸã«ãã¹ã¯ãããã® yodobashi_signup_logs ãã©ã«ããéããšããã°ãã¡ã€ã«ãšã¹ã¯ãªãŒã³ã·ã§ãããã¿ã€ã ã¹ã¿ã³ãä»ãã§èªåä¿åãããŠããŸããããããã®ãŸãŸãã¹ããšããã³ã¹ãšããŠæŽ»çšã§ããŸãã
â² èªåä¿åããããã°ãã©ã«ãã®äžèº«ããã°ãã¡ã€ã«ïŒã¹ã¯ãªãŒã³ã·ã§ãã4æãã¿ã€ã ã¹ã¿ã³ãä»ãã§æŽçãããŠãã
| è€æ°ã»ã¬ã¯ã¿ã®ãã©ãŒã«ããã¯èšèš | XPathãè€æ°ãã¿ãŒã³çšæããŠå ç¢ãªèŠçŽ ç¹å®ãå®çŸ |
| ãã°ïŒã¹ã¯ãªãŒã³ã·ã§ãã | å®è¡å±¥æŽã远跡å¯èœã«ããããšã§ãããã°å·¥æ°ãåæž |
| ç»é²âãã°ã¢ãŠãâãã°ã€ã³ã®äžè²«ãã㌠| ç»é²å®äºã ãã§ãªããã°ã€ã³å¯èœç¶æ ãŸã§æ€èšŒ |
| ã¯ã©ã¹èšèšã«ããåå©çšæ§ | åæ©èœãç¬ç«ããã¡ãœããã«åé¢ãããŠããæ¡åŒµãããã |
QAãšã³ãžãã¢ãšããŠãæ¯åæåã§ãã©ãŒã ãåããã®ã¯éçããšãã課é¡ã«å¯Ÿããå®éã®çŸå Žã§äœ¿ããã¬ãã«ã®èªååãç®æããŠèšèšããŸããããã² GitHubã®ã³ãŒããåèã«ãããªãã®ãããžã§ã¯ãã«åãããŠã«ã¹ã¿ãã€ãºããŠã¿ãŠãã ããïŒ

