参考url https://www.seleniumqref.com/
#!/usr/local/bin/python # -*- coding: utf-8 -*- import copy import getopt import os import random import re # chromedriver の入手先-> http://chromedriver.chromium.org/getting-started from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.support import expected_conditions from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait import sys import time import unittest conf = {"chrome_driver": os.getcwd() + '\\chromedriver.exe', "chrome_options" :[ #"--headless", "--enable-logging=False", "--ignore-certificate-errors", #以下、3行はSSLエラー対策らしい "--disable-extensions", "--disable-print-preview"]} class FormReConstruct(unittest.TestCase): # test前 処理 def setUp(self): chopt = webdriver.ChromeOptions() for option_tmp in conf["chrome_options"]: chopt.add_argument( option_tmp ) self.driver = webdriver.Chrome(options = chopt, executable_path=conf["chrome_driver"]) self.driver.implicitly_wait(10) # test後 処理 def tearDown(self): self.driver.close() def test_form_urls_1(self): test_url = "http://cent80.a5.jp:8080/contact2/catalog/main/form.shtml" with self.subTest(test_url=test_url): self.subtest_input_all_valid(test_url) # 全項目に正しい値を入力 self.subtest_input_text(test_url) # 各textへの入力test self.subtest_input_text_zipcode(test_url) # 郵便番号→住所変換test self.subtest_input_radio(test_url) # radioのnull test self.subtest_select_build_plan(test_url) # 選択による他項目の表示切替え test def subtest_input_all_valid(self,test_url): self.init_input_page(test_url) #入力内容に全く問題なければ、.submitBtn のelement に .js-disabled がない submit_btn = self.driver.find_element_by_class_name("submitBtn") self.assertEqual("submitBtn", submit_btn.get_attribute("class")) #上記の処理までにvalidatioとしてはOKだが、おまけでsubmitをclick submit_btn.click() def init_input_page(self,test_url): retry_limit = 5 while retry_limit: if self.init_input_page_sub(test_url): return True retry_limit -= 1 print("retry init_input_page_sub()", retry_limit) return False def init_input_page_sub(self,test_url): self.driver.get(test_url) # 対象urlへaccess # onbeforeunload イベントにより # 「ページを離れようとしています。よろしいですか?」のalertが # 表示される場合の処理 try: alert = self.driver.switch_to.alert alert.accept() except: pass # pageの全要素が読み込まれるまでwait # refer to https://qiita.com/uguisuheiankyo/items/cec03891a86dfda12c9a try: WebDriverWait(self.driver, 10).until(EC.presence_of_all_elements_located) except: print("timeout",presence_of_all_elements_located) return False # 氏名等の入力前にcatalog選択し、その後、初期値として、全項目を入力 if self.pre_input_all_valid(test_url) == False: return False if self.input_all_valid(test_url) == False: return False return True def subtest_input_text(self,test_url): # 現行のvalidationは、/request/js/common.js に定義されてます elm_names = {} elm_names["name_f"] = elm_names["name_s"] = \ [{"value":"", "valid":False }, {"value": random_str(10,["katakana_h"]), "valid":False }, {"value": random_str(10,["hiragana","katakana_z","kanji","kishuizon"]), "valid":True }, {"value": random_str(11,["hiragana","katakana_z","kanji","kishuizon"]), "valid":False}] elm_names["name_fk"] = elm_names["name_sk"] = \ [{"value":"", "valid":False }, {"value": random_str(10,["katakana_z"]), "valid":True }, {"value": random_str(11,["katakana_z"]), "valid":False }, # TODO フリガナは、全角数字やアルファベットを許さず # valudationが厳しい {"value": random_str(10,["katakana_z","number_z","alphabet_z"]), "valid":False }, {"value": random_str(10,["katakana_z","number_z"]), "valid":False }, {"value": random_str(10,["katakana_z"]), "valid":True} ] elm_names["zip_f"] = [{"value":"", "valid":False}, {"value":random_str(7,[]), "valid":False}, {"value":random_str(8,[]), "valid":False}] elm_names["add_1"] = [{"value":"", "valid":False}, {"value": random_str(100,["number_z","alphabet_z", "hiragana","kanji","kishuizon"]), "valid":True }, {"value": random_str(101,["number_z","alphabet_z", "hiragana","kanji","kishuizon"]), "valid":False }, {"value": random_str(50,[]), "valid":False }] elm_names["add_2"] = [{"value":"", "valid":False}, {"value": random_str(100,["number_z","alphabet_z", "hiragana","kanji","kishuizon"]), "valid":True }, {"value": random_str(101,["number_z","alphabet_z", "hiragana","kanji","kishuizon"]), "valid":False }, {"value": random_str(50,[]), "valid":True }] elm_names["tel1"] = [{"value":"", "valid":False}, {"value": random_str(11,[]), "valid":False}, {"value":"09012345678", "valid":True }] elm_names["email1"] = [{"value":"", "valid":False}, {"value": random_str(11,[]), "valid":False}] elm_names["hp_inquire"] = [{"value":"", "valid":True }, {"value": random_str(1500,[]), "valid":False}] for elm_name in elm_names.keys(): for test_case in elm_names[elm_name]: print(elm_name, test_case["value"], test_case["valid"] ) # 画面の初期状態として、全項目に値を入力 self.init_input_page(test_url) # 次にtest_caseにある値を入力 form_elms = self.driver.find_elements_by_name(elm_name) form_elms[0].clear() form_elms[0].send_keys(test_case["value"] + "\t") time.sleep(0.5) submit_btn = self.driver.find_element_by_class_name("submitBtn") time.sleep(1) if test_case["valid"]==False: self.assertEqual("submitBtn js-disabled", submit_btn.get_attribute("class"), elm_name +" "+ test_case["value"]) else: self.assertEqual("submitBtn", submit_btn.get_attribute("class"), elm_name +" "+ test_case["value"]) # "build_plan" により、他項目の表示/非表示が切り替わるtest def subtest_select_build_plan(self,test_url): self.init_input_page(test_url) plan_elms = self.driver.find_elements_by_name("build_plan") plan_size_elms = self.driver.find_elements_by_name("build_plan_size") plan_city_elms = self.driver.find_elements_by_name("build_plan_city") plan_area_elms = self.driver.find_elements_by_name("build_plan_area") test_cases = \ [{"plan":"お選びください", "size":False,"city":False,"area":False}, {"plan":"あり(現住所と同じ)","size":True, "city":False,"area":False}, {"plan":"あり(現住所と違う)","size":True, "city":True, "area":False}, {"plan":"なし(購入希望)", "size":True, "city":False,"area":True}] for test_case in test_cases: plan_elms[0].send_keys(test_case["plan"]) time.sleep(2) self.assertEqual(test_case["size"], plan_size_elms[0].is_displayed()) self.assertEqual(test_case["city"], plan_city_elms[0].is_displayed()) self.assertEqual(test_case["area"], plan_area_elms[0].is_displayed()) def subtest_input_radio(self,test_url): elm_defs = [{"elm_name":"sex", "valid":True }, {"elm_name":"bunjo","valid":True }] #任意項目 for elm_def in elm_defs: self.init_input_page(test_url) form_elms = self.driver.find_elements_by_name(elm_def["elm_name"]) for form_elm in form_elms: elm_name = elm_def["elm_name"] # radioはseleniumでnull化できない為、javascriptにより値をclear if form_elm.is_selected(): js_str = "".join(["for( elm of document.getElementsByName('", elm_name, "')) elm.checked = false;"]) self.driver.execute_script(js_str) submit_btn = self.driver.find_element_by_class_name("submitBtn") if elm_def["valid"]==False: self.assertEqual("submitBtn js-disabled", submit_btn.get_attribute("class"), elm_name) else: self.assertEqual("submitBtn", submit_btn.get_attribute("class"), elm_name) # 郵便番号→住所 自動変換のtest def subtest_input_text_zipcode(self,test_url): # google日本語apiにより住所へ変換していますが、 # 新しい過ぎる?郵便番号は変換できないようです zipcodes = [{"zip_f":"100-0005", "todouhuken":"東京都","add_1":"千代田区丸の内"}, {"zip_f":"1000005", "todouhuken":"東京都","add_1":"千代田区丸の内"}, {"zip_f":"150-0002", "todouhuken":"東京都","add_1":"渋谷区渋谷"}, {"zip_f":"105-8566", "todouhuken":"", "add_1":""}, # ※1 {"zip_f":"999-9999", "todouhuken":"", "add_1":""} ] # まず、対象urlへaccessし、全項目に正しく入力 self.init_input_page(test_url) for zipcode in zipcodes: zip_elms = self.driver.find_elements_by_name("zip_f") pref_elms = self.driver.find_elements_by_name("todouhuken") add_elms = self.driver.find_elements_by_name("add_1") zip_elms[0].clear() pref_elms[0].send_keys("お選びください") add_elms[0].clear() zip_elms[0].send_keys(zipcode["zip_f"]) btn_elms = self.driver.find_elements_by_css_selector("a.addressBtn") btn_elms[0].click() time.sleep(2) self.assertEqual(zipcode["todouhuken"],pref_elms[0].get_attribute("value")) self.assertEqual(zipcode["add_1"], add_elms[0].get_attribute("value") ) def pre_input_all_valid(self,test_url): # catalog一覧が表示されるまでwait selector_str = '.hmSetList__list>li' WebDriverWait(self.driver,10).until( EC.element_to_be_clickable((By.CSS_SELECTOR,selector_str) )) # catalog一覧内からrandomに選択 li_elms = self.driver.find_elements_by_css_selector(selector_str) li_pos = random.randint(0, len(li_elms)-1) try: li_elms[li_pos].click() except: print("fail click ",selector_str) return False # 「お受け取り先の入力へ」がclick可能になるまでwait x_path_str = "//span[text()='お受け取り先の入力へ']" WebDriverWait(self.driver,10).until( EC.element_to_be_clickable((By.XPATH,x_path_str) )) span_elms = self.driver.find_elements_by_xpath(x_path_str) try: span_elms[0].click() except: print("fail click ",x_path_str) return False return True def input_all_valid(self,test_url): for elm_name in form_type_a_all_valid.keys(): try: WebDriverWait(self.driver,10).until( EC.element_to_be_clickable((By.NAME,elm_name) )) except: print("timeout element_to_be_clickable",elm_name) return False elm_def = form_type_a_all_valid[elm_name] form_elms = self.driver.find_elements_by_name(elm_name) if form_elms[0].get_attribute("type")=="select-one": form_elms[0].send_keys(elm_def["value"]) elif form_elms[0].get_attribute("type")=="radio": for form_elm in form_elms: if form_elm.get_attribute("value")==elm_def["value"]: form_elm.click() form_elm.click() # 親要素の選択 # form_elm.find_element_by_xpath("..").click() break elif form_elms[0].get_attribute("type")=="checkbox" : for form_elm in form_elms: if form_elm.get_attribute("value")==elm_def["value"]: try: form_elm.click() except: print("fail click ", form_elms[0].get_attribute("type"), elm_name ) return False break else: # focos out時にvalidationされる場合もある為、タブも追加で押下げ form_elms[0].clear() form_elms[0].send_keys(elm_def["value"]+"\t") return True form_type_a_all_valid = \ {"name_f" :{"value":"テスト髙橋" }, "name_s" :{"value":"テスト①太郎" }, "name_fk" :{"value":"タカハシ" }, "name_sk" :{"value":"イチタロウ" }, "sex" :{"value":"女" }, "age" :{"value":"26~30歳" }, "job" :{"value":"会社員(事務系)" }, "zip_f" :{"value":"100-0005" }, "todouhuken" :{"value":"東京都" }, "add_1" :{"value":"千代田区丸の内" }, "add_2" :{"value":"1丁目 東京駅の住所です" }, "tel1" :{"value":"03-1234-5678" }, "email1" :{"value":"test-user-01@example.com" }, "build_clas2" :{"value":"新築" }, "build_plan" :{"value":"あり(現住所と同じ)" }, "build_plan_size" :{"value":"25坪以下(約82平方メートル以下)"}, #build_plan_size, build_plan_city, build_plan_area は #build_planの値により表示/非表示が切り替わります #"build_plan_city":{"type":"text"}, #"build_plan_area":{"type":"select-one"} "build_time" :{"value":"半年以内" }, "interest1" :{"value":"土地情報の紹介・斡旋、土地購入に関するアドバイス"}, "interest2" :{"value":"プランニングのご相談" }, "interest3" :{"value":"ファイナンシャルプランナーによる家計アドバイス" }, "interest4" :{"value":"法律家、税理士、会計士等へのご相談" }, "interest5" :{"value":"工場見学会や建築現場・ご入居者様宅の見学会" }, "build_budget" :{"value":"1500万円以下" }, "soil_budget" :{"value":"1500万円以下" }, # bunjo の項目は、選択したcatalogによっては表示されない "bunjo" :{"value":"希望する" }, "hp_inquire" :{"value":"これはテストのご意見です。\n改行を入れています。"}} def random_str(char_len,char_groups): chars = \ {"number_h" : "0123456789", "number_z" : "0123456789", "alphabet_h" : "abcdefghij", "alphabet_z" : "abcdefghij", "symbol_h" : "~!@#$%^&*(", "space" : " ", "hiragana" : "あいうえおぎゃぎょー", "katakana_z" : "アイウエオギャギョー", "katakana_h" : "アイウエオャギョー", "kanji" : "日本東京都港区虎ノ門", "kishuizon" : "㈱髙﨑①Ⅰα㍻㋿─○"} str_source = ""; if len(char_groups) > 0: for char_group in char_groups: str_source += chars[char_group] else: for char_group in chars.keys(): str_source += chars[char_group] # 元となる文字列が短い場合、random.sample()が失敗する為 while len(str_source) <= char_len: str_source += str_source random_str = "".join(random.sample(str_source, char_len)) return random_str if __name__ == "__main__": unittest.main()