def screenshots(self, file_path: str = None) -> None: """ Saves a screenshots of the current window to a PNG image file. Usage: self.screenshots() self.screenshots('/Screenshots/foo.png') """ if file_path is None: img_dir = os.path.join(os.getcwd(), "reports", "images") if os.path.exists(img_dir) is False: os.mkdir(img_dir) file_path = os.path.join(img_dir, str(time.time()).split(".")[0] + ".png") if Seldom.debug is True: log.info(f"📷️ screenshot -> ({file_path}).") Seldom.driver.save_screenshot(file_path) else: log.info("📷️ screenshot -> HTML report.") self.images.append(Seldom.driver.get_screenshot_as_base64())
def type_enter(self, text: str, clear: bool = False, index: int = 0, **kwargs) -> None: """ Enter text and enter directly. Usage: self.type_enter(css="#el", text="selenium") """ if clear is True: self.clear(index, **kwargs) web_elem = WebElement(**kwargs) elem = web_elem.get_elements(index) web_elem.show_element(elem) log.info("✅ {info} -> input '{text}' and enter.".format( info=web_elem.info, text=text)) elem.send_keys(text) elem.send_keys(Keys.ENTER)
def check_element(self, css=None): """ Check that the element exists Usage: self.check_element(css="#el") """ if css is None: raise NameError("Please enter a CSS selector") log.info("👀 check element.") js = 'return document.querySelectorAll("{css}")'.format(css=css) ret = Seldom.driver.execute_script(js) if len(ret) > 0: for i in range(len(ret)): js = 'return document.querySelectorAll("{css}")[{i}].outerHTML;'.format(css=css, i=i) ret = Seldom.driver.execute_script(js) print("{} ->".format(i), ret) else: log.warn("No elements were found.")
def assertInTitle(self, title=None, msg=None): """ Asserts whether the current title is in line with expectations. Usage: self.assertInTitle("title") """ if title is None: raise AssertionError("The assertion title cannot be empty.") for _ in range(Seldom.timeout + 1): try: self.assertIn(title, Seldom.driver.title) log.info("👀 assertIn title: {title}.".format( title=Seldom.driver.title)) break except AssertionError: sleep(1) else: log.warn("❌ assertIn fail: {title}.".format(title=title)) self.assertIn(title, Seldom.driver.title, msg=msg)
def assertInUrl(self, url=None, msg=None): """ Asserts whether the current URL is in line with expectations. Usage: self.assertInUrl("url") """ if url is None: raise AssertionError("The assertion URL cannot be empty.") for _ in range(Seldom.timeout + 1): try: self.assertIn(url, Seldom.driver.current_url) log.info("👀 assertIn url: {url}.".format( url=Seldom.driver.current_url)) break except AssertionError: sleep(1) else: log.warn("❌ assertIn fail: {url}.".format(url=url)) self.assertIn(url, Seldom.driver.current_url, msg=msg)
def assertNotText(self, text=None, msg=None): """ Asserts that the current page does not contain the specified text. Usage: self.assertNotText("text") """ if text is None: raise AssertionError("The assertion text cannot be empty.") elem = Seldom.driver.find_element_by_tag_name("html") for _ in range(Seldom.timeout + 1): if elem.is_displayed(): try: self.assertNotIn(text, elem.text) log.info("👀 assertNotText: {text}.".format(text=text)) break except AssertionError: sleep(1) else: self.assertNotIn(text, elem.text, msg=msg)
def assertElement(self, index=0, msg=None, **kwargs): """ Asserts whether the element exists. Usage: self.assertElement(css="#id") """ if msg is None: msg = "No element found" elem = True for _ in range(Seldom.timeout + 1): try: log.info("👀 assertElement.") self.get_element(index=index, **kwargs) elem = True break except NotFindElementError: elem = False sleep(1) self.assertTrue(elem, msg=msg)
def find_element(elem): """ Find if the element exists. """ for i in range(Seldom.timeout): elems = Seldom.driver.find_elements(by=elem[0], value=elem[1]) if len(elems) == 1: log.info("✅ Find element: {by}={value} ".format( by=elem[0], value=elem[1])) break elif len(elems) > 1: log.warn("❓ Find {n} elements through: {by}={value}".format( n=len(elems), by=elem[0], value=elem[1])) break else: time.sleep(1) else: error_msg = "❌ Find 0 elements through: {by}={value}".format( by=elem[0], value=elem[1]) log.error(error_msg) raise NotFindElementError(error_msg)
def osSystem(path=''): os_system = platform.system() driver = automatic() if os_system == 'Windows': log.info('当前操作系统:Windows') driver.Contrast_win(path=path) # 检查对比Windows系统环境下的Chromedriver pathWin = path + r'Browser_Driver/chromedriver.exe' return pathWin elif os_system == 'Darwin' or \ os_system == 'darwin' or \ os_system == 'Mac' or \ os_system == 'mac' or \ os_system == 'OS X': log.info('当前操作系统:Mac OS') driver.Contrast_mac(path=path) # 检查对比Mac系统环境下的Chromedriver pathMac = path + r'Browser_Driver/chromedriver' return pathMac else: log.error("当前操作系统 " + os_system) raise SystemExit(log.error(' ❌ The current operating system environment is not Windows or Mac, ' 'please confirm the current environment!!'))
def assertText(self, text=None, msg=None): """ Asserts whether the text of the current page conforms to expectations. Usage: self.assertText("text") """ if text is None: raise AssertionError("The assertion text cannot be empty.") elem = Seldom.driver.find_element_by_tag_name("html") for _ in range(Seldom.timeout): if elem.is_displayed(): try: self.assertIn(text, elem.text) log.info("👀 assertText: {text}.".format(text=text)) break except AssertionError: sleep(1) else: self.assertIn(text, elem.text, msg=msg)
def type(self, text: str, clear: bool = False, enter: bool = False, index: int = 0, **kwargs) -> None: """ Operation input box. Usage: self.type(css="#el", text="selenium") """ if clear is True: self.clear(index, **kwargs) web_elem = WebElement(**kwargs) elem = web_elem.get_elements(index) web_elem.show_element(elem) log.info("✅ {info}, input '{text}'.".format(info=web_elem.info, text=text)) elem.send_keys(text) if enter is True: elem.send_keys(Keys.ENTER)
def select(value: str = None, text: str = None, index: int = None, **kwargs) -> None: """ Constructor. A check is made that the given element is, indeed, a SELECT tag. If it is not, then an UnexpectedTagNameException is thrown. :Args: - css - element SELECT element to wrap - value - The value to match against Usage: <select name="NR" id="nr"> <option value="10" selected="">每页显示10条</option> <option value="20">每页显示20条</option> <option value="50">每页显示50条</option> </select> self.select(css="#nr", value='20') self.select(css="#nr", text='每页显示20条') self.select(css="#nr", index=2) """ web_elem = WebElement(**kwargs) elem = web_elem.get_elements(index) web_elem.show_element(elem) log.info("✅ {}, select option.".format(web_elem.info)) if value is not None: Select(elem).select_by_value(value) elif text is not None: Select(elem).select_by_visible_text(text) elif index is not None: Select(elem).select_by_index(index) else: raise ValueError( '"value" or "text" or "index" options can not be all empty.')
def create_scaffold(project_name): """ create scaffold with specified project name. """ if os.path.isdir(project_name): log.info(u"Folder {} exists, please specify a new folder name.".format( project_name)) return log.info("Start to create new test project: {}".format(project_name)) log.info("CWD: {}\n".format(os.getcwd())) def create_folder(path): os.makedirs(path) msg = "created folder: {}".format(path) log.info(msg) def create_file(path, file_content=""): with open(path, 'w') as f: f.write(file_content) msg = "created file: {}".format(path) log.info(msg) test_sample = '''import seldom class YouTest(seldom.TestCase): def test_case(self): """a simple test case """ self.open("https://www.baidu.com") self.type(id_="kw", text="seldom") self.click(css="#su") self.assertInTitle("seldom") if __name__ == '__main__': seldom.main() ''' run_test = """import seldom if __name__ == '__main__': # run test # seldom.main("./test_dir/") seldom.main("./test_dir/test_sample.py") """ create_folder(project_name) create_folder(os.path.join(project_name, "test_dir")) create_folder(os.path.join(project_name, "reports")) create_file(os.path.join(project_name, "test_dir", "test_sample.py"), test_sample) create_file(os.path.join(project_name, "run.py"), run_test)
def _run_test_case(self, suits): """ run test case """ if self.debug is False: for filename in os.listdir(os.getcwd()): if filename == "reports": break else: os.mkdir(os.path.join(os.getcwd(), "reports")) if self.report is None: now = time.strftime("%Y_%m_%d_%H_%M_%S") report_path = os.path.join(os.getcwd(), "reports", now + "_result.html") BrowserConfig.report_path = report_path else: report_path = os.path.join(os.getcwd(), "reports", self.report) with (open(report_path, 'wb')) as fp: log.info(seldom_str) if report_path.split(".")[-1] == "xml": runner = XMLTestRunner(output=fp) runner.run(suits) else: runner = HTMLTestRunner(stream=fp, title=self.title, description=self.description) runner.run(suits, rerun=self.rerun, save_last_run=self.save_last_run) log.info("generated html file: file:///{}".format(report_path)) webbrowser.open_new("file:///{}".format(report_path)) else: runner = unittest.TextTestRunner(verbosity=2) log.info( "A run the test in debug mode without generating HTML report!") log.info(seldom_str) runner.run(suits)
def tab(self): log.info("✅ {info}, tab.".format(info=self.web_elem.info)) self.elem.send_keys(Keys.TAB)
def copy(self) -> None: log.info("✅ {info}, ctrl+c.".format(info=self.web_elem.info)) if platform.system().lower() == "darwin": self.elem.send_keys(Keys.COMMAND, "c") else: self.elem.send_keys(Keys.CONTROL, "c")
def Contrast_win(self, path=''): try: log.info('正在检查本地ChromeDriver!!!') r = os.path.abspath(path + r'Browser_Driver/chromedriver.exe') version = os.popen('"'+r+'"' + r' --version').read() version = version.split(' ')[1] log.info("当前版本号:"+str(version)) except Exception as error: error log.info('❎检查不到Chromedriver,正在下载...') automatic().win_download_driver(path=path) automatic().Unpack_driver(path=path) r = os.path.abspath(path + r'Browser_Driver/chromedriver.exe') version = os.popen('"'+r+'"' + r' --version').read() version = version.split(' ')[1] log.info("当前版本号:"+str(version)) if version == automatic().get_latest_version(): log.info('✅当前系统Chromedriver已经是最新版本') else: log.info('当前系统Chromedriver不是最新版本,需要更新!!! 请等待!!!') automatic().win_download_driver(path=path) automatic().Unpack_driver(path=path)
def input(self, text=""): log.info("✅ {info}, input '{text}'.".format( info=self.web_elem.info, text=text)) self.elem.send_keys(text)
def run(path=None, base_url=None, report=None, title="Seldom Test Report", description="Test case execution", debug=False, rerun=0, save_last_run=False, timeout=10, xmlrunner=False): """ runner test case :param path: :param base_url: :param report: :param title: :param description: :param debug: :param rerun: :param save_last_run: :param timeout: :param xmlrunner: :return: """ if path is None: stack_t = inspect.stack() ins = inspect.getframeinfo(stack_t[1][0]) file_dir = os.path.dirname(os.path.abspath(ins.filename)) file_path = ins.filename if "\\" in file_path: this_file = file_path.split("\\")[-1] elif "/" in file_path: this_file = file_path.split("/")[-1] else: this_file = file_path suits = unittest.defaultTestLoader.discover(file_dir, this_file) else: if len(path) > 3: if path[-3:] == ".py": if "/" in path: path_list = path.split("/") path_dir = path.replace(path_list[-1], "") suits = unittest.defaultTestLoader.discover( path_dir, pattern=path_list[-1]) else: suits = unittest.defaultTestLoader.discover(os.getcwd(), pattern=path) else: suits = unittest.defaultTestLoader.discover(path) else: suits = unittest.defaultTestLoader.discover(path) if isinstance(timeout, int) is False: raise TypeError("Timeout {} is not integer.".format(timeout)) if isinstance(debug, bool) is False: raise TypeError("Debug {} is not Boolean type.".format(timeout)) """ Global base url, timeout and debug. """ Seldom.base_url = base_url Seldom.timeout = timeout Seldom.debug = debug if debug is False: for filename in os.listdir(os.getcwd()): if filename == "reports": break else: os.mkdir(os.path.join(os.getcwd(), "reports")) if report is None: now = time.strftime("%Y_%m_%d_%H_%M_%S") if xmlrunner is False: report = os.path.join(os.getcwd(), "reports", now + "_result.html") BrowserConfig.report_path = report else: report = os.path.join(os.getcwd(), "reports", now + ".xml") BrowserConfig.report_path = report else: report = os.path.join(os.getcwd(), "reports", report) with (open(report, 'wb')) as fp: log.info(seldom_str) if xmlrunner is False: runner = HTMLTestRunner(stream=fp, title=title, description=description) runner.run(suits, rerun=rerun, save_last_run=save_last_run) else: runner = XMLTestRunner(output=fp) runner.run(suits) log.info("generated html file: file:///{}".format(report)) else: runner = unittest.TextTestRunner(verbosity=2) log.info( "A run the test in debug mode without generating HTML report!") log.info(seldom_str) runner.run(suits)
def main(path=None, browser=None, report=None, title="Seldom Test Report", description="Test case execution", debug=False, rerun=0, save_last_run=False, driver_path=None, grid_url=None, timeout=10, xmlrunner=False): """ runner test case :param path: :param browser: :param report: :param title: :param description: :param debug: :param rerun: :param save_last_run: :param driver_path: :param grid_url: :param timeout: :param xmlrunner: :return: """ if path is None: stack_t = inspect.stack() ins = inspect.getframeinfo(stack_t[1][0]) file_dir = os.path.dirname(os.path.abspath(ins.filename)) file_path = ins.filename if "\\" in file_path: this_file = file_path.split("\\")[-1] elif "/" in file_path: this_file = file_path.split("/")[-1] else: this_file = file_path suits = unittest.defaultTestLoader.discover(file_dir, this_file) else: if len(path) > 3: if path[-3:] == ".py": if "/" in path: path_list = path.split("/") path_dir = path.replace(path_list[-1], "") suits = unittest.defaultTestLoader.discover( path_dir, pattern=path_list[-1]) else: suits = unittest.defaultTestLoader.discover(os.getcwd(), pattern=path) else: suits = unittest.defaultTestLoader.discover(path) else: suits = unittest.defaultTestLoader.discover(path) # set browser if browser is None: BrowserConfig.name = "chrome" else: BrowserConfig.name = browser BrowserConfig.grid_url = grid_url # Set browser drive path if driver_path is not None: ret = os.path.exists(driver_path) if ret is False: raise ValueError( "Browser - driven path error,Please check if the file exists. => {}" .format(driver_path)) BrowserConfig.driver_path = driver_path # set timeout if isinstance(timeout, int): Seldom.timeout = timeout else: raise TypeError("Timeout {} is not integer.".format(timeout)) # set debug Seldom.debug = debug """ Global launch browser """ Seldom.driver = b(BrowserConfig.name, BrowserConfig.driver_path, BrowserConfig.grid_url) Seldom.driver.maximize_window() if debug is False: for filename in os.listdir(os.getcwd()): if filename == "reports": break else: os.mkdir(os.path.join(os.getcwd(), "reports")) if report is None: now = time.strftime("%Y_%m_%d_%H_%M_%S") if xmlrunner is False: report = os.path.join(os.getcwd(), "reports", now + "_result.html") BrowserConfig.report_path = report else: report = os.path.join(os.getcwd(), "reports", now + ".xml") BrowserConfig.report_path = report else: report = os.path.join(os.getcwd(), "reports", report + ".html") BrowserConfig.driver_path = driver_path with (open(report, 'wb')) as fp: log.info(seldom_str) if xmlrunner is False: runner = HTMLTestRunner(stream=fp, title=title, description=description) runner.run(suits, rerun=rerun, save_last_run=save_last_run) else: runner = XMLTestRunner(output=fp) runner.run(suits) log.info("generated html file: file:///{}".format(report)) else: runner = unittest.TextTestRunner(verbosity=2) log.info( "A run the test in debug mode without generating HTML report!") log.info(seldom_str) runner.run(suits) """ Close browser globally """ Seldom.driver.quit()
def enter(self): log.info("✅ {info}, enter.".format(info=self.web_elem.info)) self.elem.send_keys(Keys.ENTER)
def create_scaffold(project_name): """ create scaffold with specified project name. """ if os.path.isdir(project_name): log.info(u"Folder {} exists, please specify a new folder name.".format( project_name)) return log.info("Start to create new test project: {}".format(project_name)) log.info("CWD: {}\n".format(os.getcwd())) def create_folder(path): os.makedirs(path) msg = "created folder: {}".format(path) log.info(msg) def create_file(path, file_content=""): with open(path, 'w') as f: f.write(file_content) msg = "created file: {}".format(path) log.info(msg) test_data = '''{ "baidu": [ ["case1", "seldom"], ["case2", "poium"], ["case3", "HTMLTestRunner"] ] } ''' test_sample = '''import seldom from seldom import file_data class SampleTest(seldom.TestCase): def test_case(self): """a simple test case """ self.open("http://www.itest.info") self.assertInUrl("itest.info") class DDTTest(seldom.TestCase): @file_data(file="data.json", key="baidu") def test_data_driver(self, _, keyword): """ data driver case """ self.open("https://www.baidu.com") self.type(id_="kw", text=keyword) self.click(css="#su") self.assertInTitle(keyword) if __name__ == '__main__': seldom.main(debug=True) ''' run_test = """import seldom if __name__ == '__main__': # run test file # seldom.main("./test_dir/test_sample.py") # run test dir seldom.main("./test_dir/") """ create_folder(project_name) create_folder(os.path.join(project_name, "test_dir")) create_folder(os.path.join(project_name, "reports")) create_folder(os.path.join(project_name, "test_data")) create_file(os.path.join(project_name, "test_data", "data.json"), test_data) create_file(os.path.join(project_name, "test_dir", "test_sample.py"), test_sample) create_file(os.path.join(project_name, "run.py"), run_test)
def __init__(self, url: str = None, desc: str = None): self.url = url self.element_obj = None self.alert_obj = None log.info("🔖 Test Case: {}".format(desc))
def sender(self, to=None, subject=None, contents=None, attachments=None): if to is None: raise ValueError("Please specify the email address to send") if subject is None: subject = 'Seldom Test Report' if contents is None: contents = """ <table width="50%" cellpadding="0" cellspacing="0" style="font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;box-sizing:border-box;display:inline-block;font-size:14px;overflow:hidden;border-radius:7px;background-color:#fff;margin:0;border:1px solid #e9e9e9" bgcolor="#fff"> <tbody> <tr style="font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;box-sizing:border-box;font-size:14px;margin:0"> <td style="font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;box-sizing:border-box;font-size:16px;vertical-align:top;color:#fff;font-weight:500;text-align:center;border-radius:3px 3px 0 0;background-color:#354052;margin:0;padding:20px" align="center" bgcolor="#354052" valign="top"> <span style="margin-top:20px;display:block"> Seldom Test Report </span> </td> </tr> <tr style="font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;box-sizing:border-box;font-size:14px;margin:0"> <td style="font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;box-sizing:border-box;font-size:14px;vertical-align:top;margin:0;padding:20px" valign="top"> <font color="#888888"> </font> <font color="#888888"> </font> <table width="100%" cellpadding="0" cellspacing="0" style="font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;box-sizing:border-box;font-size:14px;margin:0"> <tbody> <tr style="font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;box-sizing:border-box;font-size:14px;margin:0"> <td style="font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;box-sizing:border-box;font-size:14px;vertical-align:top;margin:0;padding:0 0 20px" valign="top"> 通过用例: {mail_pass} </td> </tr> <tr style="font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;box-sizing:border-box;font-size:14px;margin:0"> <td style="font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;box-sizing:border-box;font-size:14px;vertical-align:top;margin:0;padding:0 0 20px" valign="top"> 失败用例: {mail_fail} </td> </tr> <tr style="font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;box-sizing:border-box;font-size:14px;margin:0"> <td style="font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;box-sizing:border-box;font-size:14px;vertical-align:top;margin:0;padding:0 0 20px" valign="top"> 错误用例: {mail_error} </td> </tr> <tr style="font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;box-sizing:border-box;font-size:14px;margin:0"> <td style="font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;box-sizing:border-box;font-size:14px;vertical-align:top;margin:0;padding:0 0 20px" valign="top"> 跳过用例: {mail_skip} </td> </tr> </tbody> </table> <font color="#888888"> </font> </td> </tr> </tbody> </table> """.format(mail_pass=str(RunResult.passed), mail_fail=str(RunResult.failed), mail_error=str(RunResult.errors), mail_skip=str(RunResult.skiped)) msg = MIMEMultipart() msg['Subject'] = Header(subject, 'utf-8') msg['From'] = self.user msg['To'] = to text = MIMEText(contents, 'html', 'utf-8') msg.attach(text) if attachments is None: attachments = BrowserConfig.report_path att_name = "report.html" if "\\" in attachments: att_name = attachments.split("\\")[-1] if "/" in attachments: att_name = attachments.split("/")[-1] att = MIMEApplication(open(attachments, 'rb').read()) att['Content-Type'] = 'application/octet-stream' att["Content-Disposition"] = 'attachment; filename="{}"'.format( att_name) msg.attach(att) smtp = smtplib.SMTP() smtp.connect(self.host) smtp.login(self.user, self.password) smtp.sendmail(self.user, to, msg.as_string()) smtp.quit() log.info("Email sent successfully!!")
def paste(self): log.info("✅ {info}, ctrl+v.".format(info=self.web_elem.info)) if platform.system().lower() == "darwin": self.elem.send_keys(Keys.COMMAND, "v") else: self.elem.send_keys(Keys.CONTROL, "v")
def backspace(self): log.info("✅ {info}, backspace.".format(info=self.web_elem.info)) self.elem.send_keys(Keys.BACKSPACE)
def delete(self): log.info("✅ {info}, delete.".format(info=self.web_elem.info)) self.elem.send_keys(Keys.DELETE)
def create_file(path, file_content=""): with open(path, 'w') as f: f.write(file_content) msg = "created file: {}".format(path) log.info(msg)
def create_folder(path): os.makedirs(path) msg = "created folder: {}".format(path) log.info(msg)
def space(self): log.info("✅ {info}, space.".format(info=self.web_elem.info)) self.elem.send_keys(Keys.SPACE)