wms整体框架
This commit is contained in:
parent
bdb446b411
commit
2a2e35d1b7
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
|
@ -0,0 +1,33 @@
|
|||
from selenium import webdriver
|
||||
|
||||
|
||||
def check_overlap(component1, component2):
|
||||
driver = webdriver.Chrome() # 初始化浏览器驱动,这里使用Chrome
|
||||
|
||||
try:
|
||||
# 打开页面或者进行其他操作以加载组件
|
||||
# ...
|
||||
|
||||
# 获取组件1的位置和大小
|
||||
location1 = component1.location
|
||||
size1 = component1.size
|
||||
x1, y1 = location1['x'], location1['y']
|
||||
width1, height1 = size1['width'], size1['height']
|
||||
|
||||
# 获取组件2的位置和大小
|
||||
location2 = component2.location
|
||||
size2 = component2.size
|
||||
x2, y2 = location2['x'], location2['y']
|
||||
width2, height2 = size2['width'], size2['height']
|
||||
|
||||
# 判断是否有重叠的地方
|
||||
if (x1 < x2 + width2 and x1 + width1 > x2 and
|
||||
y1 < y2 + height2 and y1 + height1 > y2):
|
||||
overlap = True
|
||||
else:
|
||||
overlap = False
|
||||
|
||||
return overlap
|
||||
|
||||
finally:
|
||||
driver.quit() # 关闭浏览器驱动
|
|
@ -10,22 +10,38 @@
|
|||
import os
|
||||
import time
|
||||
from pywinauto import Desktop
|
||||
from pywinauto.keyboard import send_keys
|
||||
|
||||
def upload_files(file_path, *args):
|
||||
|
||||
def upload_files(file_path):
|
||||
"""
|
||||
:param file_path: files path which geometry files in directory
|
||||
:param args: file name about geometry files
|
||||
"""
|
||||
|
||||
app = Desktop()
|
||||
# select the explorer file popover
|
||||
shon = app["Select Geometry Files"]
|
||||
# accept the one or more files to write into input box
|
||||
for i in args:
|
||||
send_keys('"{}"'.format(i))
|
||||
url_tab = shon["Toolbar3"]
|
||||
url_tab.click()
|
||||
# input url of the geometry files
|
||||
send_keys(file_path)
|
||||
send_keys("{VK_RETURN}")
|
||||
time.sleep(1)
|
||||
shon["打开(O)"].click_input()
|
||||
dialog = app['打开']
|
||||
# 根据名字找到弹出窗口
|
||||
dialog["Edit"].type_keys(file_path)
|
||||
# 在弹出的框中输入相关的值。
|
||||
dialog["Button"].click()
|
||||
|
||||
|
||||
|
||||
# def upload_files(file_path, *args):
|
||||
# """
|
||||
# :param file_path: files path which geometry files in directory
|
||||
# :param args: file name about geometry files
|
||||
# """
|
||||
# app = Desktop()
|
||||
# # select the explorer file popover
|
||||
# shon = app["Select Geometry Files"]
|
||||
# # accept the one or more files to write into input box
|
||||
# for i in args:
|
||||
# send_keys('"{}"'.format(i))
|
||||
# url_tab = shon["Toolbar3"]
|
||||
# url_tab.click()
|
||||
# # input url of the geometry files
|
||||
# send_keys(file_path)
|
||||
# send_keys("{VK_RETURN}")
|
||||
# time.sleep(1)
|
||||
# shon["打开(O)"].click_input()
|
||||
|
|
|
@ -1,23 +1,29 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
-------------------------------------------------
|
||||
File Name: image
|
||||
Description : 颜色识别的工具类
|
||||
Author : xiaobei
|
||||
CreateDate: 2023/3/12 10:17
|
||||
-------------------------------------------------
|
||||
# ==================================================
|
||||
# @Time : 2023-03-23 13:55:01
|
||||
# @Author : 小北
|
||||
# @微信:xiaobei_upup
|
||||
# @Email : 2211484376@qq.com
|
||||
# @QQ群:585971269
|
||||
# @微信群:可加我微信拉你
|
||||
# @Site : 苏州
|
||||
# @Desc : 颜色识别工具类,元素截图工具函数
|
||||
# @跳槽辅导:初中高级测试跳槽涨薪面试辅导,详情咨询微信
|
||||
# @求职辅导:初中高级测试求职面试辅导,详情咨询微信
|
||||
# @特色: 小北独创VIP面试速成课程,拿下心仪的offer
|
||||
# ==================================================
|
||||
"""
|
||||
import cv2
|
||||
import numpy as np
|
||||
import collections
|
||||
import tempfile
|
||||
import os, random
|
||||
import time
|
||||
|
||||
from PIL import Image
|
||||
#pillow
|
||||
|
||||
|
||||
# pillow
|
||||
|
||||
def getColorList():
|
||||
"""
|
||||
|
@ -25,15 +31,18 @@ def getColorList():
|
|||
Returns:
|
||||
|
||||
"""
|
||||
dict = collections.defaultdict(list)
|
||||
# collections.defaultdict是一个字典子类,它在初始化时会指定默认的值类型。当你访问字典中不存在的键时,它会返回指定类型的默认值,而不是抛出KeyError异常。在这里,我们使用list作为默认值类型,所以当你访问dict中不存在的键时,它会返回一个空列表。
|
||||
dict = collections.defaultdict(list) # 创建一个字典,每一个字典的key对应的是一个list,等会在list中添加颜色的取值范围的数组就可以作为一种颜色了,dict内部是这样的数据结构 --> {“black” : "[array([ 0, 0, 0]), array([180, 255, 55])]" }
|
||||
|
||||
|
||||
# 黑色
|
||||
lower_black = np.array([0, 0, 0])
|
||||
upper_black = np.array([180, 255, 55])
|
||||
lower_black = np.array([0, 0, 0]) # 固定写法,了解即可
|
||||
upper_black = np.array([180, 255, 55]) # 在HSV颜色空间中,H通道(色调)的取值范围是0到180,S通道(饱和度)的取值范围是0到255,V通道(亮度)的取值范围是0到55。
|
||||
color_list = []
|
||||
color_list.append(lower_black)
|
||||
color_list.append(lower_black) # 在list中将numpy数组添加到list的末尾
|
||||
color_list.append(upper_black)
|
||||
dict['black'] = color_list
|
||||
# print(dict['black']) # 打印黑色的HSV空间的取值范围 输出[array([ 0, 0, 0]), array([180, 255, 55])]
|
||||
|
||||
# 灰色
|
||||
lower_gray = np.array([0, 0, 55])
|
||||
|
@ -121,6 +130,7 @@ def getColorList():
|
|||
def get_color(image_path, shield_list=None):
|
||||
"""
|
||||
获取指定图片的主体颜色,有且只会返回一种颜色
|
||||
函数解释:根据图像中与给定颜色字典中的颜色最匹配的区域来确定图像的主要颜色。它首先排除了在shield_list中指定的黑色颜色,然后对剩余的颜色进行比较,并找到面积最大的区域对应的颜色作为结果返回。如果没有找到符合条件的颜色,则返回None
|
||||
Args:
|
||||
image_path:待处理的图片路径
|
||||
shield_list: 需要屏蔽掉的颜色列表。
|
||||
|
@ -128,21 +138,21 @@ def get_color(image_path, shield_list=None):
|
|||
'green'(绿色),'cyan'(青色),'blue'(蓝色),'purple'(紫色)
|
||||
|
||||
Returns: 返回指定图片的主体颜色的字符串,例如'black'。如果是纯色图片,且该颜色被屏蔽,则返回None
|
||||
|
||||
"""
|
||||
if shield_list is None:
|
||||
shield_list = []
|
||||
image_frame = cv2.imread(image_path)
|
||||
hsv = cv2.cvtColor(image_frame, cv2.COLOR_BGR2HSV)
|
||||
shield_list = [] # 检测是否为none,如果是就置为空list,否则会报错
|
||||
image_frame = cv2.imread(image_path) # 这是opencv库中的imread函数读取图像文件,然后加载到image_frame中
|
||||
hsv = cv2.cvtColor(image_frame, cv2.COLOR_BGR2HSV) # 将RGB图像转换为HSV颜色空间,方便上述的color去对照
|
||||
maxsum = -100
|
||||
color = None
|
||||
color_dict = getColorList()
|
||||
color_dict = getColorList() # 获取颜色字典大全
|
||||
for black_color in shield_list:
|
||||
if black_color in color_dict:
|
||||
color_dict.pop(black_color)
|
||||
color_dict.pop(black_color) # 遍历是否有需要屏蔽的颜色,如果有就从字典中移除,后续识别过程中就会屏蔽该颜色
|
||||
tmp_num = random.randint(0, 99)
|
||||
color_dict_len = len(color_dict)
|
||||
same_pic = 0
|
||||
# 以下的循环是找到图片中颜色面积最大的颜色,作为返回结果,否则就none,不用详细记忆过程
|
||||
for d in color_dict:
|
||||
mask = cv2.inRange(hsv, color_dict[d][0], color_dict[d][1])
|
||||
# cv2.imwrite(os.path.join(tempfile.gettempdir(), f"{d}_{tmp_num}.jpg"), mask)
|
||||
|
@ -166,25 +176,25 @@ def get_color(image_path, shield_list=None):
|
|||
|
||||
def get_screenshot_by_element(driver, element):
|
||||
"""
|
||||
获取指定元素的截图(android)
|
||||
获取指定元素的截图(android/web通用)
|
||||
Args:
|
||||
driver: appium驱动
|
||||
driver: appium驱动 或者selenium驱动
|
||||
element: 要获取截图的元素
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
# 先截取整个屏幕,存储至系统临时目录下
|
||||
|
||||
TEMP_FILE = os.path.join(tempfile.gettempdir(), f"temp_screen_{int(time.time()*1000)}.png")
|
||||
# 先截取整个屏幕/浏览器页面,存储至screenshots目录下
|
||||
TEMP_FILE = os.path.join("./screenshots", f"temp_screen_{int(time.time() * 1000)}.png")
|
||||
driver.get_screenshot_as_file(TEMP_FILE)
|
||||
|
||||
# 获取元素四角坐标
|
||||
# 获取页面上需要截图的元素的四角坐标
|
||||
location = element.location
|
||||
size = element.size
|
||||
|
||||
# 截取图片
|
||||
TEMP_FILE_2 = os.path.join(tempfile.gettempdir(), f"temp_screen_{int(time.time()*1000)}.png")
|
||||
# 截取具体目标元素的图片
|
||||
TEMP_FILE_2 = os.path.join("./screenshots", f"temp_screen_{int(time.time() * 1000)}.png")
|
||||
# 截取整张图片中的某一个目标元素的图片,并存到TEMP_FILE_2路径的screenshots目录下
|
||||
cut_image(TEMP_FILE, location["x"], location["y"], location["x"] + size["width"], location["y"] + size["height"],
|
||||
TEMP_FILE_2)
|
||||
return TEMP_FILE_2
|
||||
|
@ -203,7 +213,7 @@ def get_screenshot_by_percent(driver, out_image_path=None, x1=0, y1=0, x2=1, y2=
|
|||
"""
|
||||
根据百分比截取屏幕截图
|
||||
Args:
|
||||
driver: appium驱动
|
||||
driver: appium驱动/webdriver驱动
|
||||
out_image_path: 截图结果输出路径
|
||||
x1: 所要截取区域左上角坐标的横坐标占屏幕宽度的百分比。0<=x1<=1
|
||||
y1: 所要截取区域左上角坐标的纵坐标占屏幕宽度的百分比。0<=y1<=1
|
||||
|
@ -215,7 +225,7 @@ def get_screenshot_by_percent(driver, out_image_path=None, x1=0, y1=0, x2=1, y2=
|
|||
"""
|
||||
# 先截取整个屏幕,存储至系统临时目录下
|
||||
|
||||
TEMP_FILE = os.path.join(tempfile.gettempdir(), f"temp_screen_{int(time.time()*1000)}.png")
|
||||
TEMP_FILE = os.path.join("./screenshots", f"temp_screen_{int(time.time() * 1000)}.png")
|
||||
driver.get_screenshot_as_file(TEMP_FILE)
|
||||
|
||||
# 截取图片
|
||||
|
@ -236,7 +246,7 @@ def cut_image(input_image_path, x1, y1, x2, y2, out_image_path, use_percent=Fals
|
|||
use_percent: 是否启用百分比模式,默认为不启用
|
||||
"""
|
||||
if not out_image_path:
|
||||
out_image_path = os.path.join(tempfile.gettempdir(), f"temp_screen_{int(time.time()*1000)}.png")
|
||||
out_image_path = os.path.join("./screenshots", f"temp_screen_{int(time.time() * 1000)}.png")
|
||||
image = Image.open(input_image_path) # 读取原始图片
|
||||
if use_percent:
|
||||
size = image.size # 获取图片的尺寸
|
||||
|
@ -245,14 +255,14 @@ def cut_image(input_image_path, x1, y1, x2, y2, out_image_path, use_percent=Fals
|
|||
x2 = size[0] * x2
|
||||
y2 = size[1] * y2
|
||||
box = (x1, y1, x2, y2) # 设定截取区域
|
||||
newImage = image.crop(box) # 进行截取操作
|
||||
newImage = image.crop(box) # 进行截取操作【这是核心函数,传入指定坐标就可以抠图】
|
||||
newImage.save(out_image_path) # 保存截取结果
|
||||
return out_image_path
|
||||
|
||||
|
||||
def get_color_by_element(driver, element, shield_list=None):
|
||||
"""
|
||||
获取指定元素的主体颜色
|
||||
获取指定元素的主体颜色【常用】
|
||||
Args:
|
||||
driver: appium驱动
|
||||
element: 要获取颜色的元素
|
||||
|
@ -266,12 +276,14 @@ def get_color_by_element(driver, element, shield_list=None):
|
|||
if __name__ == '__main__':
|
||||
# filename = 'ios_h.png'
|
||||
# filename = 'C:\\Users\\viruser.v-desktop\\Desktop\\tmp\\white.png'
|
||||
filename = 'D:\\img\\323232.png'
|
||||
# filename = 'D:\\img\\323232.png'
|
||||
|
||||
filename = r"E:\Develop\Python\selenium_projects\xiaobei_selenium_automation\screenshots\blue.jpg"
|
||||
# filename = 'ios_l.png'
|
||||
# filename = 'and_h.png'
|
||||
# filename = 'and_l.png'
|
||||
print(get_color(filename, shield_list=['white']))
|
||||
print(get_color(filename, shield_list=['blue']))
|
||||
print(get_color(filename))
|
||||
# file_list = ['ios_h.png', 'ios_l.png', 'and_h.png', 'and_l.png']
|
||||
# for i in file_list:
|
||||
# frame = cv2.imread(i)
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
"""
|
||||
from PIL import Image
|
||||
import ddddocr
|
||||
|
||||
|
||||
def image_identify(driver, ele, whole_name, crop_name):
|
||||
"""
|
||||
:param driver: 浏览器驱动
|
||||
|
@ -27,10 +29,10 @@ def image_identify(driver, ele, whole_name, crop_name):
|
|||
:return: 返回验证码识别出来的字符串
|
||||
"""
|
||||
driver.save_screenshot(whole_name)
|
||||
left = ele.location['x'] + 220
|
||||
top = ele.location['y'] + 90
|
||||
right = ele.size['width'] + left + 85
|
||||
height = ele.size['height'] + top + 15
|
||||
left = ele.location['x']
|
||||
top = ele.location['y']
|
||||
right = ele.size['width'] + left
|
||||
height = ele.size['height'] + top
|
||||
|
||||
img = Image.open(whole_name).crop((left, top, right, height))
|
||||
img.save(crop_name)
|
||||
|
@ -40,4 +42,4 @@ def image_identify(driver, ele, whole_name, crop_name):
|
|||
image = f.read()
|
||||
res = ocr.classification(image)
|
||||
print(res)
|
||||
return res
|
||||
return res
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
from PIL import Image
|
||||
"""
|
||||
验证图片是否被损坏
|
||||
"""
|
||||
|
||||
def check_image_file(filepath):
|
||||
try:
|
||||
with Image.open(filepath) as img:
|
||||
img.verify()
|
||||
except OSError:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
print(check_image_file("crop_pic.png"))
|
||||
print(check_image_file("1.png"))
|
||||
|
||||
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 8.4 KiB |
|
@ -0,0 +1,70 @@
|
|||
from selenium import webdriver
|
||||
|
||||
"""
|
||||
配置了浏览器的options会加快用例执行速度,所以这里的配置也是优化框架的一步
|
||||
"""
|
||||
def options1():
|
||||
options = webdriver.ChromeOptions()
|
||||
# 页面加载策略
|
||||
options.page_load_strategy = 'normal'
|
||||
# 窗体最大化
|
||||
options.add_argument('start-maximized')
|
||||
# 指定浏览器的启动坐标
|
||||
# options.add_argument('window-position=500,500')
|
||||
# 指定浏览器的窗体大小
|
||||
# options.add_argument('window-size=1200,800')
|
||||
# 去掉浏览器的自动化黄条:目前的阶段下已经不是那么有需要的了。
|
||||
options.add_experimental_option('excludeSwitches', ['enable-automation', 'enable-logging'])
|
||||
# options.add_experimental_option('disable-infobars') # 只限于python2.7的版本有效,现在已经失效
|
||||
|
||||
# 无头模式:不在桌面生成浏览器的运行,浏览器作为后台程序,静默后台运行。虽然无法肉眼看到,但实际上一切照旧,该运行的依旧会正常运行。可以减少测试设备的资源损耗。一般可用于持续集成中,虽然有可能出现错误。
|
||||
# options.add_argument('--headless')
|
||||
|
||||
# 去掉账号密码保存弹窗
|
||||
prefs = {
|
||||
'credentials_enable_service': False,
|
||||
'profile.password_manager_enable': False
|
||||
}
|
||||
options.add_experimental_option("prefs", prefs)
|
||||
# 加载本地缓存信息:Selenium默认启动的浏览器是不会加载本地缓存的。
|
||||
'''
|
||||
1. 该功能可以实现验证码的绕过,但前提条件是需要提前手动登录一次(只对可以记住登录状态的网站有效)。
|
||||
2. 该功能可以起到一定程度的反爬效果,具体根据被访问系统的反爬机制而决定
|
||||
3. 该功能的使用,只能够在一个浏览器生效,如果在启动之前开启有其他的chrome浏览器,则该功能无法生效,会报错。一定要关闭所有浏览器以后再运行webdriver
|
||||
'''
|
||||
# 自动化测试不会处理验证码,因为验证码本身就是防止自动化脚本的。
|
||||
# options.add_argument(r"--user-data-dir=C:\Users\15414\AppData\Local\Google\Chrome\User Data")
|
||||
|
||||
# options中的一些常用参数设置如下:
|
||||
|
||||
# 启动隐身模式
|
||||
# options.add_argument('incognito')
|
||||
# 去除控制台多余的信息:避免掉无用的信息内容
|
||||
# options.add_experimental_option('excludeSwitches', ['enable-logging'])
|
||||
options.add_argument('--log_level=3') # 设置 Chrome 浏览器的日志级别
|
||||
'''
|
||||
--log_level=3 日志级别
|
||||
在生产环境中,一般建议将日志级别设置为较低的级别(如 3)以减少日志量。而在开发和调试过程中,你可能需要更详细的日志信息,可以将日志级别设置得更高(如 1)
|
||||
0:DEFAULT,使用默认日志记录级别。
|
||||
1:VERBOSE,输出详细的日志信息,包括调试信息。
|
||||
2:INFO,输出一般的信息级别日志。
|
||||
3:WARNING,输出警告级别的日志。
|
||||
4:ERROR,输出错误级别的日志。
|
||||
5:FATAL,输出严重错误级别的日志。
|
||||
'''
|
||||
options.add_argument('--disable-gpu') # 禁用 GPU 加速
|
||||
options.add_argument(
|
||||
'--ignore-certificate-errors') # 它用于忽略证书错误,当 Chrome 浏览器访问一个使用无效或过期的 SSL 证书的网站时,会弹出一个警告页面,提示用户连接不安全。通过添加 --ignore-certificate-errors 这个选项,可以告诉 Chrome 浏览器忽略这些证书错误,继续加载页面而不显示警告。
|
||||
options.add_argument("--no-sandbox") # 禁用沙盒模式
|
||||
options.add_argument("--disable-extensions") # 禁用扩展
|
||||
# options.add_argument("--headless") # 使用无头模式运行浏览器
|
||||
# options.add_argument("--window-size=1920,1080") # 自定义窗口大小
|
||||
# options.add_argument("--blink-settings=imagesEnabled=false") # 禁用图片加载
|
||||
# options.add_argument("--user-agent=Your User Agent String") # 使用用户代理
|
||||
options.add_argument("--lang=en-US") # 设置为英文(美国)
|
||||
# 禁用浏览器自动化控制警告提示
|
||||
options.add_experimental_option("excludeSwitches", ["enable-automation"])
|
||||
options.add_experimental_option("useAutomationExtension", False)
|
||||
|
||||
# 返回options对象
|
||||
return options
|
|
@ -0,0 +1,34 @@
|
|||
from PIL import Image
|
||||
import io
|
||||
|
||||
|
||||
def compare_images(image1, image2):
|
||||
|
||||
with open(image1, 'rb') as file:
|
||||
image1_data = file.read()
|
||||
|
||||
with open(image2, 'rb') as file:
|
||||
image2_data = file.read()
|
||||
img1 = Image.open(io.BytesIO(image1_data))
|
||||
img2 = Image.open(io.BytesIO(image2_data))
|
||||
print("这里可以输出图片的相关属性,如大小、格式等", img1)
|
||||
if img1.size != img2.size:
|
||||
return False
|
||||
|
||||
pairs = zip(img1.getdata(), img2.getdata())
|
||||
print(img1.getdata())
|
||||
if len(img1.getbands()) == 1:
|
||||
# for grayscale images
|
||||
dif = sum(abs(p1 - p2) for p1, p2 in pairs)
|
||||
else:
|
||||
# for RGB images
|
||||
dif = sum(abs(c1 - c2) for p1, p2 in pairs for c1, c2 in zip(p1, p2))
|
||||
|
||||
ncomponents = img1.size[0] * img1.size[1] * 3
|
||||
similarity = (ncomponents - dif) / ncomponents
|
||||
|
||||
# 设置阈值,即两张图片相似度严格达到99%才认为它们完全一样
|
||||
return similarity > 0.99
|
||||
|
||||
|
||||
compare_images("crop_pic.png", "crop_pic.png")
|
|
@ -1,45 +0,0 @@
|
|||
"""
|
||||
-------------------------------------------------
|
||||
File Name:
|
||||
Description :
|
||||
Author : xiaobei
|
||||
CreateDate:
|
||||
wechat:xiaobei_upup
|
||||
-------------------------------------------------
|
||||
"""
|
||||
import os
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.chrome.options import Options
|
||||
import pytest
|
||||
|
||||
|
||||
class ScreenshotUtil:
|
||||
def __init__(self):
|
||||
self.driver = None
|
||||
|
||||
def create_driver(self):
|
||||
options = Options()
|
||||
options.add_argument('--headless')
|
||||
options.add_argument('--disable-gpu')
|
||||
self.driver = webdriver.Chrome(chrome_options=options)
|
||||
|
||||
def take_screenshot(self, name):
|
||||
if not self.driver:
|
||||
self.create_driver()
|
||||
self.driver.get_screenshot_as_file(os.path.join(os.getcwd(), f"{name}.png"))
|
||||
|
||||
def close_driver(self):
|
||||
if self.driver:
|
||||
self.driver.quit()
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def screenshot():
|
||||
screenshot_util = ScreenshotUtil()
|
||||
yield screenshot_util
|
||||
screenshot_util.close_driver()
|
||||
|
||||
|
||||
def test_take_screenshot(screenshot):
|
||||
screenshot.take_screenshot("test")
|
||||
assert os.path.isfile(os.path.join(os.getcwd(), "test.png"))
|
|
@ -0,0 +1,14 @@
|
|||
from selenium.webdriver import ActionChains
|
||||
|
||||
|
||||
def slide(drivers, element, x, y):
|
||||
# ------------鼠标滑动操作------------
|
||||
action = ActionChains(drivers)
|
||||
# 第一步:在滑块处按住鼠标左键
|
||||
action.click_and_hold(element)
|
||||
# 第二步:相对鼠标当前位置进行移动
|
||||
action.move_by_offset(x, y)
|
||||
# 第三步:释放鼠标
|
||||
action.release()
|
||||
# 执行动作
|
||||
action.perform()
|
|
@ -0,0 +1,24 @@
|
|||
def calculate_equation(equation):
|
||||
# 提取等式中的第二个字符
|
||||
operator = equation[1]
|
||||
|
||||
# 提取表达式
|
||||
expression = equation[:3]
|
||||
|
||||
# 根据运算符进行计算并得出结果
|
||||
if operator == "+":
|
||||
result = eval(expression)
|
||||
print(expression)
|
||||
elif operator == "-":
|
||||
result = eval(expression)
|
||||
elif operator == "*":
|
||||
result = eval(expression)
|
||||
elif operator == "/":
|
||||
result = eval(expression)
|
||||
else:
|
||||
result = None
|
||||
|
||||
# 返回计算结果
|
||||
return result
|
||||
|
||||
print(calculate_equation("3+8=?"))
|
|
@ -0,0 +1,11 @@
|
|||
import pytesseract
|
||||
from PIL import Image
|
||||
|
||||
# 打开验证码图片
|
||||
captcha_image = Image.open('captcha.png')
|
||||
|
||||
# 使用 OCR 对验证码图片进行识别
|
||||
captcha_text = pytesseract.image_to_string(captcha_image)
|
||||
|
||||
# 输出识别结果
|
||||
print(captcha_text)
|
|
@ -52,6 +52,11 @@ class ConfigManager(object):
|
|||
ZHUIFENG = "https://exam.wzzz.fun"
|
||||
WPS_LOGIN = "https://account.wps.cn/"
|
||||
FILE_UPLOAD = "https://letcode.in/file"
|
||||
WMS_URL = "http://192.168.10.129/login?redirect=%2Findex"
|
||||
WHOLE_PATH = "./screenshots/简单验证码.png"
|
||||
CROP_PATH = "./screenshots/crop_pic.png"
|
||||
USERNAME = "admin"
|
||||
PASSWORD = "123456"
|
||||
@property
|
||||
def log_file(self):
|
||||
"""日志目录"""
|
||||
|
|
40
conftest.py
40
conftest.py
|
@ -3,6 +3,8 @@
|
|||
import pytest
|
||||
from selenium import webdriver
|
||||
|
||||
from common.options_chrome import options1
|
||||
|
||||
"""
|
||||
-------------------------------------------------
|
||||
File Name:
|
||||
|
@ -17,9 +19,10 @@ test_pytest.fixture 这个实现了和unittest的setup,teardown一样的前置
|
|||
管理数据库连接,全局管理我们的driver
|
||||
"""
|
||||
|
||||
|
||||
@pytest.fixture(scope='session', autouse=True)
|
||||
def drivers():
|
||||
driver = webdriver.Chrome()
|
||||
driver = webdriver.Chrome(options=options1())
|
||||
driver.maximize_window()
|
||||
yield driver
|
||||
driver.quit()
|
||||
|
@ -33,29 +36,6 @@ def drivers():
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# @test_pytest.fixture(scope='session', autouse=True)
|
||||
# def drivers(request):
|
||||
# global driver
|
||||
# if driver is None:
|
||||
# driver = webdriver.Chrome()
|
||||
# driver.maximize_window()
|
||||
#
|
||||
# def fn():
|
||||
# driver.quit()
|
||||
#
|
||||
# request.addfinalizer(fn)
|
||||
# return driver
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
# @test_pytest.fixture(scope='session', autouse=True)
|
||||
# def drivers():
|
||||
# global driver
|
||||
|
@ -73,18 +53,6 @@ def drivers():
|
|||
# driver.quit()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# @test_pytest.hookimpl(hookwrapper=True)
|
||||
# def pytest_runtest_makereport(item):
|
||||
# """
|
||||
|
|
|
@ -17,13 +17,14 @@ from selenium.webdriver.support.ui import WebDriverWait
|
|||
|
||||
# Map PageElement constructor arguments to webdriver locator enums
|
||||
_LOCATOR_MAP = {
|
||||
'xpath': By.XPATH,
|
||||
'id': By.ID,
|
||||
'tag_name': By.TAG_NAME,
|
||||
'name': By.NAME,
|
||||
'css': By.CSS_SELECTOR,
|
||||
'class1':By.CLASS_NAME
|
||||
}
|
||||
'xpath': By.XPATH,
|
||||
'id': By.ID,
|
||||
'tag_name': By.TAG_NAME,
|
||||
'name': By.NAME,
|
||||
'css': By.CSS_SELECTOR,
|
||||
'class1': By.CLASS_NAME
|
||||
}
|
||||
|
||||
|
||||
class PageObject(object):
|
||||
"""
|
||||
|
@ -40,6 +41,7 @@ class PageObject(object):
|
|||
"""接收driver,为了让driver后续完全脱手,再也不接触driver而写,让测试者能够拜托driver的繁琐操作。"""
|
||||
self.w = webdriver
|
||||
|
||||
|
||||
class PageElement(object):
|
||||
"""Page Element descriptor.
|
||||
:param xpath: `str`
|
||||
|
@ -56,7 +58,7 @@ class PageElement(object):
|
|||
raise ValueError("Please specify a locator")
|
||||
if len(kwargs) > 1:
|
||||
raise ValueError("Please specify only one locator")
|
||||
k, v = next(iter(kwargs.items())) # 使用了迭代器,生成器来让(id='kw')变成By.id, 'kw'两个单独的参数
|
||||
k, v = next(iter(kwargs.items())) # 使用了迭代器,生成器来让(id='kw')变成By.id, 'kw'两个单独的参数
|
||||
self.locator = (_LOCATOR_MAP[k], v)
|
||||
self.has_context = bool(context)
|
||||
|
||||
|
@ -83,6 +85,74 @@ class PageElement(object):
|
|||
elem.send_keys(value)
|
||||
|
||||
|
||||
class PageElements(object):
|
||||
"""Page Element descriptor.
|
||||
|
||||
:param accessibility_id: `str`
|
||||
Use this accessibility_id locator
|
||||
:param xpath: `str`
|
||||
Use this xpath locator
|
||||
:param ios_predicate: `str`
|
||||
Use this ios_predicate locator
|
||||
:param uiautomator: `str`
|
||||
Use this uiautomator locator
|
||||
:param uiautomation: `str`
|
||||
Use this uiautomation locator
|
||||
|
||||
:param context: `bool`
|
||||
This element is expected to be called with context
|
||||
|
||||
Page Elements are used to access elements on a page. The are constructed
|
||||
using this factory method to specify the locator for the element.
|
||||
|
||||
elem1 = PageElement(css='div.myclass')
|
||||
elem2 = PageElement(id_='foo')
|
||||
elem_with_context = PageElement(name='bar', context=True)
|
||||
|
||||
Page Elements act as property descriptors for their Page Object, you can get
|
||||
and set them as normal attributes.
|
||||
"""
|
||||
|
||||
def __init__(self, context=False, **kwargs):
|
||||
if not kwargs:
|
||||
raise ValueError("Please specify a locator")
|
||||
if len(kwargs) > 1:
|
||||
raise ValueError("Please specify only one locator")
|
||||
k, v = next(iter(kwargs.items()))
|
||||
self.locator = (_LOCATOR_MAP[k], v)
|
||||
self.has_context = bool(context)
|
||||
|
||||
def find(self, context):
|
||||
try:
|
||||
ele = WebDriverWait(context, 3, 1).until(lambda x: x.find_elements(*self.locator))
|
||||
except NoSuchElementException:
|
||||
return None
|
||||
except TimeoutException:
|
||||
return None
|
||||
else:
|
||||
return ele
|
||||
|
||||
def __get__(self, instance, owner, context=None):
|
||||
if not instance:
|
||||
return None
|
||||
|
||||
if not context and self.has_context:
|
||||
return lambda ctx: self.__get__(instance, owner, context=ctx)
|
||||
|
||||
if not context:
|
||||
context = instance.w
|
||||
|
||||
return self.find(context)
|
||||
|
||||
def __set__(self, instance, value):
|
||||
if self.has_context:
|
||||
raise ValueError("Sorry, the set descriptor doesn't support elements with context.")
|
||||
elem = self.__get__(instance, instance.__class__)
|
||||
if not elem:
|
||||
raise ValueError("Can't set value, element not found")
|
||||
elem.send_keys(value)
|
||||
|
||||
|
||||
# Backwards compatibility with previous versions that used factory methods
|
||||
page_element = PageElement
|
||||
|
||||
page_elements = PageElements
|
||||
|
|
|
@ -0,0 +1,210 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
-------------------------------------------------
|
||||
File Name: basePage
|
||||
Description : Python descriptor
|
||||
Author : beige
|
||||
CreateDate: 2023/03/19 21:36
|
||||
-------------------------------------------------
|
||||
"""
|
||||
from selenium import webdriver
|
||||
from selenium.common.exceptions import NoSuchElementException, TimeoutException
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
|
||||
# Map PageElement constructor arguments to webdriver locator enums
|
||||
_LOCATOR_MAP = {
|
||||
'xpath': By.XPATH,
|
||||
'id': By.ID,
|
||||
'tag_name': By.TAG_NAME,
|
||||
'name': By.NAME,
|
||||
'css_selector': By.CSS_SELECTOR
|
||||
}
|
||||
class PageObject(object):
|
||||
"""Page Object pattern.
|
||||
|
||||
:param webdriver: `selenium.webdriver.WebDriver`
|
||||
Selenium webdriver instance
|
||||
:param root_uri: `str`
|
||||
Root URI to base any calls to the ``PageObject.get`` method. If not defined
|
||||
in the constructor it will try and look it from the webdriver object.
|
||||
"""
|
||||
|
||||
def __init__(self, webdriver: object, root_uri: object = None) -> object:
|
||||
"""
|
||||
|
||||
:rtype:
|
||||
"""
|
||||
self.w = webdriver
|
||||
self.root_uri = root_uri if root_uri else getattr(self.w, 'root_uri', None)
|
||||
|
||||
def get(self, uri):
|
||||
"""
|
||||
:param uri: URI to GET, based off of the root_uri attribute.
|
||||
"""
|
||||
root_uri = self.root_uri or ''
|
||||
self.w.get(root_uri + uri)
|
||||
|
||||
class PageElement(object):
|
||||
"""Page Element descriptor.
|
||||
|
||||
:param accessibility_id: `str`
|
||||
Use this accessibility_id locator
|
||||
:param xpath: `str`
|
||||
Use this xpath locator
|
||||
:param ios_predicate: `str`
|
||||
Use this ios_predicate locator
|
||||
:param uiautomator: `str`
|
||||
Use this uiautomator locator
|
||||
:param uiautomation: `str`
|
||||
Use this uiautomation locator
|
||||
|
||||
:param context: `bool`
|
||||
This element is expected to be called with context
|
||||
|
||||
Page Elements are used to access elements on a page. The are constructed
|
||||
using this factory method to specify the locator for the element.
|
||||
|
||||
elem1 = PageElement(css='div.myclass')
|
||||
elem2 = PageElement(id_='foo')
|
||||
elem_with_context = PageElement(name='bar', context=True)
|
||||
|
||||
Page Elements act as property descriptors for their Page Object, you can get
|
||||
and set them as normal attributes.
|
||||
"""
|
||||
|
||||
def __init__(self, context=False, **kwargs):
|
||||
if not kwargs:
|
||||
raise ValueError("Please specify a locator")
|
||||
if len(kwargs) > 1:
|
||||
raise ValueError("Please specify only one locator")
|
||||
k, v = next(iter(kwargs.items()))
|
||||
self.locator = (_LOCATOR_MAP[k], v)
|
||||
self.has_context = bool(context)
|
||||
|
||||
def find(self, context):
|
||||
try:
|
||||
ele = WebDriverWait(context, 5, 1).until(lambda x: x.find_element(*self.locator))
|
||||
except NoSuchElementException:
|
||||
return None
|
||||
except TimeoutException:
|
||||
return None
|
||||
else:
|
||||
return ele
|
||||
|
||||
def __get__(self, instance, owner, context=None):
|
||||
if not instance:
|
||||
return None
|
||||
|
||||
if not context and self.has_context:
|
||||
return lambda ctx: self.__get__(instance, owner, context=ctx)
|
||||
|
||||
if not context:
|
||||
context = instance.w
|
||||
|
||||
return self.find(context)
|
||||
|
||||
def __set__(self, instance, value):
|
||||
if self.has_context:
|
||||
raise ValueError("Sorry, the set descriptor doesn't support elements with context.")
|
||||
elem = self.__get__(instance, instance.__class__)
|
||||
if not elem:
|
||||
raise ValueError("Can't set value, element not found")
|
||||
elem.send_keys(value)
|
||||
|
||||
|
||||
class PageElements(object):
|
||||
"""Page Element descriptor.
|
||||
|
||||
:param accessibility_id: `str`
|
||||
Use this accessibility_id locator
|
||||
:param xpath: `str`
|
||||
Use this xpath locator
|
||||
:param ios_predicate: `str`
|
||||
Use this ios_predicate locator
|
||||
:param uiautomator: `str`
|
||||
Use this uiautomator locator
|
||||
:param uiautomation: `str`
|
||||
Use this uiautomation locator
|
||||
|
||||
:param context: `bool`
|
||||
This element is expected to be called with context
|
||||
|
||||
Page Elements are used to access elements on a page. The are constructed
|
||||
using this factory method to specify the locator for the element.
|
||||
|
||||
elem1 = PageElement(css='div.myclass')
|
||||
elem2 = PageElement(id_='foo')
|
||||
elem_with_context = PageElement(name='bar', context=True)
|
||||
|
||||
Page Elements act as property descriptors for their Page Object, you can get
|
||||
and set them as normal attributes.
|
||||
"""
|
||||
|
||||
def __init__(self, context=False, **kwargs):
|
||||
if not kwargs:
|
||||
raise ValueError("Please specify a locator")
|
||||
if len(kwargs) > 1:
|
||||
raise ValueError("Please specify only one locator")
|
||||
k, v = next(iter(kwargs.items()))
|
||||
self.locator = (_LOCATOR_MAP[k], v)
|
||||
self.has_context = bool(context)
|
||||
|
||||
def find(self, context):
|
||||
try:
|
||||
ele = WebDriverWait(context, 3, 1).until(lambda x: x.find_elements(*self.locator))
|
||||
except NoSuchElementException:
|
||||
return None
|
||||
except TimeoutException:
|
||||
return None
|
||||
else:
|
||||
return ele
|
||||
|
||||
def __get__(self, instance, owner, context=None):
|
||||
if not instance:
|
||||
return None
|
||||
|
||||
if not context and self.has_context:
|
||||
return lambda ctx: self.__get__(instance, owner, context=ctx)
|
||||
|
||||
if not context:
|
||||
context = instance.w
|
||||
|
||||
return self.find(context)
|
||||
|
||||
def __set__(self, instance, value):
|
||||
if self.has_context:
|
||||
raise ValueError("Sorry, the set descriptor doesn't support elements with context.")
|
||||
elem = self.__get__(instance, instance.__class__)
|
||||
if not elem:
|
||||
raise ValueError("Can't set value, element not found")
|
||||
elem.send_keys(value)
|
||||
|
||||
|
||||
class MultiPageElement(PageElement):
|
||||
""" Like `PageElement` but returns multiple results.
|
||||
all_table_rows = MultiPageElement(tag='tr')
|
||||
elem2 = PageElement(id_='foo')
|
||||
elem_with_context = PageElement(tag='tr', context=True)
|
||||
"""
|
||||
|
||||
def find(self, context):
|
||||
try:
|
||||
return context.find_elements(*self.locator)
|
||||
except NoSuchElementException:
|
||||
return []
|
||||
|
||||
def __set__(self, instance, value):
|
||||
if self.has_context:
|
||||
raise ValueError("Sorry, the set descriptor doesn't support elements with context.")
|
||||
elems = self.__get__(instance, instance.__class__)
|
||||
if not elems:
|
||||
raise ValueError("Can't set value, no elements found")
|
||||
[elem.send_keys(value) for elem in elems]
|
||||
|
||||
|
||||
# Backwards compatibility with previous versions that used factory methods
|
||||
page_element = PageElement
|
||||
page_elements = PageElements
|
||||
multi_page_element = MultiPageElement
|
|
@ -0,0 +1,102 @@
|
|||
from page.basePage import *
|
||||
|
||||
"""
|
||||
-------------------------------------------------
|
||||
File Name:
|
||||
Description :
|
||||
Author : xiaobei
|
||||
CreateDate:
|
||||
wechat:xiaobei_upup
|
||||
-------------------------------------------------
|
||||
"""
|
||||
"""
|
||||
在平时中我们应该养成写注释的习惯,因为过一段时间后,没有注释,代码读起来很费劲。
|
||||
"""
|
||||
|
||||
|
||||
class WmsElements(PageObject):
|
||||
# 登录页面
|
||||
username = PageElement(xpath='//*[@id="app"]/div/form/div[1]/div/div/input')
|
||||
password = PageElement(xpath='//*[@id="app"]/div/form/div[2]/div/div/input')
|
||||
image = PageElement(class1='login-code-img')
|
||||
image_input = PageElement(xpath='//*[@id="app"]/div/form/div[3]/div/div[1]/input')
|
||||
login_button = PageElement(xpath='//*[@id="app"]/div/form/div[4]/div/button[1]')
|
||||
|
||||
# 登出页面
|
||||
logout_icon = PageElement(xpath='//*[@id="app"]/div/div[2]/div[1]/div[1]/div[3]/div[2]/div/i')
|
||||
# logout_button = PageElement(class1='//*[@id="dropdown-menu-1380"]/li') # 这里的xpath是定位不到的,不知道为啥,是一个无序列表中的li。
|
||||
logout_button = PageElement(class1="el-dropdown-menu__item--divided") # 采用classname来定位,因为是唯一定位的。
|
||||
sure_logout = PageElement(xpath="/html/body/div[3]/div/div[3]/button[2]")
|
||||
dismiss_logout = PageElement(xpath='/html/body/div[3]/div/div[3]/button[1]')
|
||||
yes_or_no_logout_text = PageElement(xpath='/html/body/div[3]/div/div[2]/div[1]/div[2]/p')
|
||||
|
||||
|
||||
|
||||
# 系统工具页面元素
|
||||
system_tools = PageElement(xpath='//*[@id="app"]/div/div[1]/div[2]/div[1]/div/ul/div[8]/li/div')
|
||||
form_generate = PageElement(xpath='//*[@id="app"]/div/div[1]/div[2]/div[1]/div/ul/div[8]/li/ul/div[1]/a/li')
|
||||
form_generate_icon = PageElement(
|
||||
xpath='//*[@id="app"]/div/div[1]/div[2]/div[1]/div/ul/div[8]/li/ul/div[1]/a/li/svg/use')
|
||||
code_gen = PageElement(xpath='//*[@id="app"]/div/div[1]/div[2]/div[1]/div/ul/div[8]/li/ul/div[2]/a/li')
|
||||
code_gen_icon = PageElement(xpath='//*[@id="app"]/div/div[1]/div[2]/div[1]/div/ul/div[8]/li/ul/div[2]/a/li/svg')
|
||||
system_interface = PageElement(xpath='//*[@id="app"]/div/div[1]/div[2]/div[1]/div/ul/div[8]/li/ul/div[3]/a/li')
|
||||
system_interface_icon = PageElement(
|
||||
xpath='//*[@id="app"]/div/div[1]/div[2]/div[1]/div/ul/div[8]/li/ul/div[3]/a/li/svg')
|
||||
|
||||
# 表单构建页面
|
||||
form_gen_logo = PageElement(xpath='//*[@id="app"]/div/div[2]/section/div/div[1]/div[1]/div')
|
||||
upload_element_button = PageElement(
|
||||
xpath='//*[@id="app"]/div/div[2]/section/div/div[1]/div[2]/div[1]/div/div/div[4]/div[13]/div')
|
||||
upload_button = PageElement(
|
||||
xpath='//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[2]/div/div/div/div/button')
|
||||
upload_button_icon = PageElement(
|
||||
xpath='//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[2]/div/div/div/div/button/i')
|
||||
upload_name = PageElement(
|
||||
xpath='//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[2]/div/label')
|
||||
delete_upload = PageElement(
|
||||
xpath='//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[2]/span[2]')
|
||||
|
||||
input_phone_number = PageElement(
|
||||
xpath='//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[1]/div/div/div/input')
|
||||
right_number = PageElement(
|
||||
xpath='//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[1]/div/div/div/span[2]/span/span/span')
|
||||
|
||||
def click_log_in_button(self):
|
||||
"""点击搜索"""
|
||||
return self.login_button.click()
|
||||
|
||||
def click_system_tools(self):
|
||||
"""点击搜索"""
|
||||
return self.system_tools.click()
|
||||
|
||||
def click_form_generate(self):
|
||||
"""点击搜索"""
|
||||
return self.form_generate.click()
|
||||
|
||||
def click_upload_element_button(self):
|
||||
"""点击搜索"""
|
||||
return self.upload_element_button.click()
|
||||
|
||||
def click_upload_button(self):
|
||||
"""点击搜索"""
|
||||
return self.upload_button.click()
|
||||
|
||||
def click_delete_upload(self):
|
||||
"""点击搜索"""
|
||||
return self.delete_upload.click()
|
||||
|
||||
def click_logout_icon(self):
|
||||
"""点击搜索"""
|
||||
return self.logout_icon.click()
|
||||
|
||||
def click_logout_button(self):
|
||||
"""点击搜索"""
|
||||
return self.logout_button.click()
|
||||
|
||||
def click_sure_logout(self):
|
||||
"""点击搜索"""
|
||||
return self.sure_logout.click()
|
||||
|
||||
def click_dismiss_logout(self):
|
||||
"""点击搜索"""
|
||||
return self.dismiss_logout.click()
|
|
@ -0,0 +1,28 @@
|
|||
from page.basePage import *
|
||||
|
||||
"""
|
||||
-------------------------------------------------
|
||||
File Name:
|
||||
Description :
|
||||
Author : xiaobei
|
||||
CreateDate:
|
||||
wechat:xiaobei_upup
|
||||
-------------------------------------------------
|
||||
"""
|
||||
"""
|
||||
在平时中我们应该养成写注释的习惯,因为过一段时间后,没有注释,代码读起来很费劲。
|
||||
"""
|
||||
|
||||
|
||||
class WmsElements(PageObject):
|
||||
# input_account = find_elements(By.CLASS_NAME, "el-input__inner")
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def click_log_in_button(self):
|
||||
"""点击搜索"""
|
||||
return self.log_in_button.click()
|
||||
|
||||
|
||||
|
11
pytest.ini
11
pytest.ini
|
@ -6,15 +6,16 @@ addopts =
|
|||
-vs
|
||||
--clean-alluredir
|
||||
--alluredir=./reports/
|
||||
-m "smoke"
|
||||
-m "test1"
|
||||
-n 0
|
||||
--reruns=0
|
||||
|
||||
;注册 mark 标记
|
||||
markers =
|
||||
smoke: marks tests as smoke
|
||||
test: marks tests as test
|
||||
smoke: 冒烟用例
|
||||
test: 仅供调试的用例
|
||||
testNow: marks tests as testNow
|
||||
test1 : temporary test
|
||||
;执行的时候使用 pytest -m smoke
|
||||
|
||||
minversion = 5.0
|
||||
|
@ -26,10 +27,10 @@ minversion = 5.0
|
|||
testpaths =./testcases/
|
||||
|
||||
;模块名的规则,配置测试搜索的模块文件名称
|
||||
python_files = test*.py
|
||||
python_files = test_*.py
|
||||
|
||||
;类名的规则,配置测试搜索的测试类名
|
||||
python_classes = Test*
|
||||
|
||||
;方法名的规则,配置测试搜索的测试函数名
|
||||
python_functions = test
|
||||
python_functions = test_*
|
|
@ -3,6 +3,10 @@ pytest
|
|||
allure-pytest
|
||||
pytest-xdist
|
||||
pytest-rerunfailures
|
||||
pytest-ordering
|
||||
pillow
|
||||
pywinauto
|
||||
ddddocr
|
||||
ddddocr
|
||||
pyyaml
|
||||
requests
|
||||
opencv-python
|
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
Binary file not shown.
After Width: | Height: | Size: 7.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.2 MiB |
Binary file not shown.
After Width: | Height: | Size: 294 KiB |
|
@ -0,0 +1,215 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
# ==================================================
|
||||
# @Time : 2023-06-23 13:55:01
|
||||
# @Author : 小北
|
||||
# @微信:xiaobei_upup
|
||||
# @Email : 2211484376@qq.com
|
||||
# @QQ群:585971269
|
||||
# @微信群:可加我微信拉你
|
||||
# @Site : 苏州
|
||||
# @Desc :
|
||||
# @跳槽辅导:初中高级测试跳槽涨薪面试辅导,详情咨询微信
|
||||
# @求职辅导:初中高级测试求职面试辅导,详情咨询微信
|
||||
# @特色: 小北独创VIP面试速成课程,拿下心仪的offer
|
||||
# @如何付款:先拿offer再付款,只需交定金,相互信任无套路
|
||||
# ==================================================
|
||||
"""
|
||||
import pytest
|
||||
from pywinauto import Desktop
|
||||
from selenium.common import NoSuchElementException
|
||||
from selenium.webdriver import ActionChains
|
||||
from selenium.webdriver.common import actions
|
||||
from selenium.webdriver.common.by import By
|
||||
|
||||
from page.zhuifeng_pages.zhuifeng_index import zhuifeng_index_page
|
||||
from page.wms_pages.wms_elements import WmsElements
|
||||
from config.conf import ConfigManager
|
||||
import time
|
||||
from common.image_identify import image_identify
|
||||
from common.file_upload import upload_files
|
||||
|
||||
|
||||
class TestUploadElement:
|
||||
# @pytest.fixture(scope='function', autouse=True)
|
||||
# def login_logout(self, drivers):
|
||||
# """登录wms网站然后pytest的测试用例执行完后再执行登出操作"""
|
||||
# drivers.get(ConfigManager.WMS_URL)
|
||||
#
|
||||
# yield
|
||||
# print("后置")
|
||||
|
||||
# @pytest.mark.test1
|
||||
@pytest.mark.parametrize('username, password', [
|
||||
('admin', '123456')
|
||||
])
|
||||
def test_001_add_upload_element(self, drivers, username, password):
|
||||
"""
|
||||
在一个def用例里面,如果有一个assert执行失败,那么整个用例都会停下来,所以要将用例原子化一些
|
||||
"""
|
||||
# 访问网址
|
||||
drivers.get(ConfigManager.WMS_URL)
|
||||
|
||||
account = drivers.find_elements(By.CLASS_NAME, "el-input__inner")[0]
|
||||
account.send_keys(username)
|
||||
password1 = drivers.find_elements(By.CLASS_NAME, "el-input__inner")[1]
|
||||
password1.send_keys(password)
|
||||
|
||||
time.sleep(3)
|
||||
|
||||
login = drivers.find_elements(By.CLASS_NAME, "el-button")[0]
|
||||
assert login.text == "登 录"
|
||||
assert login.is_displayed() == True
|
||||
login.click()
|
||||
|
||||
|
||||
|
||||
churuku = drivers.find_elements(By.CLASS_NAME, "el-submenu__title")[2]
|
||||
churuku.click()
|
||||
# ruku = drivers.find_element(By.CLASS_NAME, "el-menu-item")
|
||||
# ruku.click()
|
||||
systemtool = drivers.find_elements(By.CLASS_NAME, "el-submenu__title")[4]
|
||||
systemtool.click()
|
||||
time.sleep(2)
|
||||
ul = drivers.find_element(By.CLASS_NAME, "el-menu--inline")
|
||||
|
||||
# li = ul.find_elements(By.TAG_NAME, "li")[0]
|
||||
li = ul.find_element(By.XPATH, '//*[@id="app"]/div/div[1]/div[2]/div[1]/div/ul/div[8]/li/ul/div[1]/a')
|
||||
assert li.is_displayed() == True
|
||||
li.click()
|
||||
time.sleep(2)
|
||||
form_gen = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[1]/div[1]/div')
|
||||
assert form_gen.text == "Form Generator"
|
||||
|
||||
|
||||
upload = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[1]/div[2]/div[1]/div/div/div[4]/div[13]/div')
|
||||
upload.click()
|
||||
|
||||
|
||||
# uploadbutton = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[2]/div/div/div/div/button')
|
||||
# uploadbutton.click()
|
||||
#
|
||||
# app = Desktop()
|
||||
# dialog = app['打开']
|
||||
# # 根据名字找到弹出窗口
|
||||
# dialog["Edit"].type_keys(r'E:\Develop\Python\selenium_projects\xiaobei_selenium_automation\common\img.png')
|
||||
# # 在弹出的框中输入相关的值。
|
||||
# dialog["Button"].click()
|
||||
# time.sleep(3)
|
||||
#
|
||||
# # 对文件上传的图标断言
|
||||
# icon = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[2]/div/div/div/div/button/i')
|
||||
# assert icon.is_displayed() == True
|
||||
# button_name = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[2]/div/div/div/div/button/span')
|
||||
# assert button_name.text == "点击上传"
|
||||
#
|
||||
# head_upload_name = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[2]/div/label')
|
||||
# assert head_upload_name.text == "上传"
|
||||
#
|
||||
#
|
||||
# # 最后删除添加的各个组件
|
||||
# delete_icon = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[2]/span[2]')
|
||||
# delete_icon.click()
|
||||
#
|
||||
# # 判断文件上传组件是否删除
|
||||
# # try:
|
||||
# # button = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[2]/div')
|
||||
# # except NoSuchElementException:
|
||||
# # raise AssertionError(f"组件 {button} 不存在") # 当一个用例里面出现了抛出异常的情况,那么def函数用例也会停止执行,一旦发现测试用例失败(包括断言失败、异常抛出等),pytest 将立即停止执行其他的测试用例,以减少不必要的运行时间。
|
||||
#
|
||||
# # 对于input框的操作
|
||||
# input_phone_number = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[1]/div/div/div/input')
|
||||
# input_phone_number.send_keys("17205290079")
|
||||
# input_phone_number.clear()
|
||||
# time.sleep(5)
|
||||
# right_number = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[1]/div/div/div/span[2]/span/span/span')
|
||||
# assert input_phone_number.get_attribute("placeholder") == "请输入手机号" # 获取input框中的默认提示语
|
||||
# # assert right_number.text == "0/11" # 这里有一个bug,由于电话号码都被clear清空了,后面的数据应该为0,而不是11,这里断言发现了一个bug,然后手动复现也是有这个bug的,然后就提bug了。
|
||||
# input_phone_number.send_keys("17205290078")
|
||||
# right_number.click()
|
||||
#
|
||||
# assert right_number.text == "11/11"
|
||||
# assert input_phone_number.get_attribute("value") == "17205290078" # 对刚刚输入input框的str做断言,不能用text,因为是断言非用户输入的文本,后者是断言用户输入的文本,这里也可以在面试中如果被问道查看测试报告中的一些断言报错,就可以说这个。
|
||||
|
||||
# ------------鼠标滑动操作------------
|
||||
# action = ActionChains(drivers)
|
||||
# # 第一步:在滑块处按住鼠标左键
|
||||
# action.click_and_hold(upload)
|
||||
# # 第二步:相对鼠标当前位置进行移动
|
||||
# action.move_by_offset(300, 300)
|
||||
# # 第三步:释放鼠标
|
||||
# action.release()
|
||||
# # 执行动作
|
||||
# action.perform()
|
||||
#
|
||||
# time.sleep(5)
|
||||
|
||||
def test_002_upload_files(self, drivers):
|
||||
|
||||
uploadbutton = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[2]/div/div/div/div/button')
|
||||
uploadbutton.click()
|
||||
|
||||
app = Desktop()
|
||||
dialog = app['打开']
|
||||
# 根据名字找到弹出窗口
|
||||
dialog["Edit"].type_keys(r'E:\Develop\Python\selenium_projects\xiaobei_selenium_automation\common\img.png')
|
||||
# 在弹出的框中输入相关的值。
|
||||
dialog["Button"].click()
|
||||
time.sleep(3)
|
||||
|
||||
|
||||
# # 对文件上传的图标断言
|
||||
# icon = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[2]/div/div/div/div/button/i')
|
||||
# assert icon.is_displayed() == True
|
||||
# button_name = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[2]/div/div/div/div/button/span')
|
||||
# assert button_name.text == "点击上传"
|
||||
#
|
||||
# head_upload_name = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[2]/div/label')
|
||||
# assert head_upload_name.text == "上传"
|
||||
#
|
||||
#
|
||||
# # 最后删除添加的各个组件
|
||||
# delete_icon = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[2]/span[2]')
|
||||
# delete_icon.click()
|
||||
#
|
||||
# # 判断文件上传组件是否删除
|
||||
# # try:
|
||||
# # button = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[2]/div')
|
||||
# # except NoSuchElementException:
|
||||
# # raise AssertionError(f"组件 {button} 不存在") # 当一个用例里面出现了抛出异常的情况,那么def函数用例也会停止执行,一旦发现测试用例失败(包括断言失败、异常抛出等),pytest 将立即停止执行其他的测试用例,以减少不必要的运行时间。
|
||||
#
|
||||
# # 对于input框的操作
|
||||
# input_phone_number = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[1]/div/div/div/input')
|
||||
# input_phone_number.send_keys("17205290079")
|
||||
# input_phone_number.clear()
|
||||
# time.sleep(5)
|
||||
# right_number = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[1]/div/div/div/span[2]/span/span/span')
|
||||
# assert input_phone_number.get_attribute("placeholder") == "请输入手机号" # 获取input框中的默认提示语
|
||||
# # assert right_number.text == "0/11" # 这里有一个bug,由于电话号码都被clear清空了,后面的数据应该为0,而不是11,这里断言发现了一个bug,然后手动复现也是有这个bug的,然后就提bug了。
|
||||
# input_phone_number.send_keys("17205290078")
|
||||
# right_number.click()
|
||||
#
|
||||
# assert right_number.text == "11/11"
|
||||
# assert input_phone_number.get_attribute("value") == "17205290078" # 对刚刚输入input框的str做断言,不能用text,因为是断言非用户输入的文本,后者是断言用户输入的文本,这里也可以在面试中如果被问道查看测试报告中的一些断言报错,就可以说这个。
|
||||
|
||||
# ------------鼠标滑动操作------------
|
||||
# action = ActionChains(drivers)
|
||||
# # 第一步:在滑块处按住鼠标左键
|
||||
# action.click_and_hold(upload)
|
||||
# # 第二步:相对鼠标当前位置进行移动
|
||||
# action.move_by_offset(300, 300)
|
||||
# # 第三步:释放鼠标
|
||||
# action.release()
|
||||
# # 执行动作
|
||||
# action.perform()
|
||||
#
|
||||
# time.sleep(5)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,222 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
# ==================================================
|
||||
# @Time : 2023-06-23 13:55:01
|
||||
# @Author : 小北
|
||||
# @微信:xiaobei_upup
|
||||
# @Email : 2211484376@qq.com
|
||||
# @QQ群:585971269
|
||||
# @微信群:可加我微信拉你
|
||||
# @Site : 苏州
|
||||
# @Desc :
|
||||
# @跳槽辅导:初中高级测试跳槽涨薪面试辅导,详情咨询微信
|
||||
# @求职辅导:初中高级测试求职面试辅导,详情咨询微信
|
||||
# @特色: 小北独创VIP面试速成课程,拿下心仪的offer
|
||||
# @如何付款:先拿offer再付款,只需交定金,相互信任无套路
|
||||
# ==================================================
|
||||
"""
|
||||
import pytest
|
||||
from pywinauto import Desktop
|
||||
from selenium.common import NoSuchElementException
|
||||
from selenium.webdriver import ActionChains
|
||||
from selenium.webdriver.common import actions
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support.wait import WebDriverWait
|
||||
|
||||
from common.slide import slide
|
||||
from common.imageColor import *
|
||||
from common.yanzhengma_jiajian import calculate_equation
|
||||
from page.zhuifeng_pages.zhuifeng_index import zhuifeng_index_page
|
||||
from page.wms_pages.wms_elements import WmsElements
|
||||
from config.conf import ConfigManager
|
||||
import time
|
||||
from common.image_identify import image_identify
|
||||
from common.file_upload import upload_files
|
||||
from page.wms_pages.form_generate.form_gen import WmsElements
|
||||
|
||||
"""
|
||||
test_pytest.fixture + 生成器yield 一起实现了和unittest的setup,teardown一样的前置启动,后置清理的装饰器
|
||||
"""
|
||||
|
||||
|
||||
@pytest.fixture(scope='class', autouse=True)
|
||||
def login_logout(drivers):
|
||||
"""登录wms网站然后pytest的测试用例执行完后再执行登出操作"""
|
||||
drivers.get(ConfigManager.WMS_URL)
|
||||
form_gen = WmsElements(drivers)
|
||||
form_gen.username = ConfigManager.USERNAME
|
||||
form_gen.password = ConfigManager.PASSWORD
|
||||
# 填写登录时候的验证码
|
||||
# yzm = image_identify(drivers, form_gen.image, ConfigManager.WHOLE_PATH, ConfigManager.CROP_PATH)
|
||||
# form_gen.image_input = calculate_equation(yzm)
|
||||
|
||||
time.sleep(3)
|
||||
form_gen.click_log_in_button()
|
||||
yield
|
||||
form_gen.click_logout_icon()
|
||||
time.sleep(2)
|
||||
# WebDriverWait(drivers, 5, 1).until(lambda x: x.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/div[1]/div[1]/div[3]/div[2]/div'))
|
||||
form_gen.click_logout_button()
|
||||
time.sleep(3)
|
||||
form_gen.click_sure_logout()
|
||||
|
||||
# form_gen.click_logout_icon()
|
||||
# form_gen.click_logout_button()
|
||||
# time.sleep(3)
|
||||
|
||||
|
||||
class TestSearch:
|
||||
@pytest.mark.test1
|
||||
def test_001(self, drivers):
|
||||
"""
|
||||
在一个def用例里面,如果有一个assert执行失败,那么整个用例都会停下来,所以要将用例原子化一些
|
||||
"""
|
||||
# global button
|
||||
# input1 = drivers.find_elements(By.CLASS_NAME, "el-input__inner")[0]
|
||||
# input1 = drivers.find_element(By.XPATH, '//*[@id="app"]/div/form/div[1]/div/div/input')
|
||||
# input1.send_keys(username1)
|
||||
# input2 = drivers.find_elements(By.CLASS_NAME, "el-input__inner")[1]
|
||||
# input2 = drivers.find_element(By.XPATH, '//*[@id="app"]/div/form/div[2]/div/div/input')
|
||||
# input2.send_keys(password1)
|
||||
# image = drivers.find_element(By.CLASS_NAME, "login-code-img")
|
||||
|
||||
# login = drivers.find_elements(By.CLASS_NAME, "el-button")[0]
|
||||
# assert login.text == "登 录"
|
||||
# login.click()
|
||||
# assert login.is_displayed() == True
|
||||
|
||||
# time.sleep(2)
|
||||
# zhufeng.image_code = image_identify(drivers, zhufeng.image, '简单验证码.png', 'crop_pic.png')
|
||||
|
||||
# churuku = drivers.find_elements(By.CLASS_NAME, "el-submenu__title")[2]
|
||||
# churuku.click()
|
||||
# ruku = drivers.find_element(By.CLASS_NAME, "el-menu-item")
|
||||
# ruku.click()
|
||||
# systemtool = drivers.find_elements(By.CLASS_NAME, "el-submenu__title")[4]
|
||||
# systemtool.click()
|
||||
|
||||
form_gen = WmsElements(drivers)
|
||||
form_gen.click_system_tools()
|
||||
# print(get_color(get_screenshot_by_element(drivers, form_gen.system_tools), shield_list=['white']))
|
||||
# print(get_color(get_screenshot_by_element(drivers, form_gen.system_tools), shield_list=['white']))
|
||||
|
||||
# ul = drivers.find_element(By.CLASS_NAME, "el-menu--inline")
|
||||
|
||||
# li = ul.find_elements(By.TAG_NAME, "li")[0]
|
||||
# li = ul.find_element(By.XPATH, '//*[@id="app"]/div/div[1]/div[2]/div[1]/div/ul/div[8]/li/ul/div[1]/a')
|
||||
time.sleep(2)
|
||||
# 点击系统工具后的表单构建的li是否展示出来
|
||||
# assert form_gen.form_generate.is_displayed() == True
|
||||
# assert form_gen.form_generate.text == "表单构建"
|
||||
# assert form_gen.form_generate_icon.is_displayed() == True
|
||||
|
||||
# assert form_gen.code_gen.is_displayed() == True
|
||||
# assert form_gen.code_gen.text == "代码生成"
|
||||
# assert form_gen.code_gen_icon.is_displayed() == True
|
||||
|
||||
# assert form_gen.system_interface.is_displayed() == True
|
||||
# assert form_gen.system_interface.text == "系统接口"
|
||||
# assert form_gen.form_generate_icon.is_displayed() == True
|
||||
|
||||
form_gen.click_form_generate()
|
||||
|
||||
# assert form_gen.form_gen_logo.text == "Form Generator"
|
||||
|
||||
form_gen.click_upload_element_button()
|
||||
|
||||
# 断言文件上传按钮是蓝色
|
||||
# assert get_color(get_screenshot_by_element(drivers, form_gen.upload_button), shield_list=['white']) == "blue"
|
||||
assert get_color_by_element(drivers, form_gen.upload_button, shield_list=['white']) == "blue"
|
||||
|
||||
# assert form_gen.upload_button.text == "点击上传"
|
||||
|
||||
form_gen.click_upload_button()
|
||||
|
||||
upload_files(r'E:\Develop\Python\selenium_projects\xiaobei_selenium_automation\common\img.png')
|
||||
|
||||
# upload = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[1]/div[2]/div[1]/div/div/div[4]/div[13]/div')
|
||||
# upload.click()
|
||||
|
||||
# uploadbutton = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[2]/div/div/div/div/button')
|
||||
# uploadbutton.click()
|
||||
|
||||
# app = Desktop()
|
||||
# dialog = app['打开']
|
||||
# # 根据名字找到弹出窗口
|
||||
# dialog["Edit"].type_keys(r'E:\Develop\Python\selenium_projects\xiaobei_selenium_automation\common\img.png')
|
||||
# # 在弹出的框中输入相关的值。
|
||||
# dialog["Button"].click()
|
||||
|
||||
# 对文件上传的图标断言
|
||||
# icon = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[2]/div/div/div/div/button/i')
|
||||
# assert form_gen.upload_button_icon.is_displayed() == True
|
||||
|
||||
# button_name = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[2]/div/div/div/div/button/span')
|
||||
# assert button_name.text == "点击上传"
|
||||
|
||||
# head_upload_name = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[2]/div/label')
|
||||
# assert form_gen.upload_name.text == "上传"
|
||||
|
||||
# 最后删除添加的各个组件
|
||||
# delete_icon = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[2]/span[2]')
|
||||
# delete_icon.click()
|
||||
form_gen.click_delete_upload()
|
||||
|
||||
# 判断文件上传组件是否删除
|
||||
# try:
|
||||
# button = drivers.find_element(By.XPATH, '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[2]/div')
|
||||
# except NoSuchElementException:
|
||||
# raise AssertionError(f"组件 {button} 不存在") # 当一个用例里面出现了抛出异常的情况,那么def函数用例也会停止执行,一旦发现测试用例失败(包括断言失败、异常抛出等),pytest 将立即停止执行其他的测试用例,以减少不必要的运行时间。
|
||||
slide(drivers, form_gen.upload_element_button, 300, 300)
|
||||
# assert form_gen.upload_button.text == "点击上传"
|
||||
|
||||
|
||||
@pytest.mark.test
|
||||
def test_002_delete_upload(self, drivers):
|
||||
form_gen = WmsElements(drivers)
|
||||
form_gen.click_system_tools()
|
||||
form_gen.click_form_generate()
|
||||
# 对于input框的操作
|
||||
# input_phone_number = drivers.find_element(By.XPATH,
|
||||
# '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[1]/div/div/div/input')
|
||||
# input_phone_number.send_keys("17205290079")
|
||||
# input_phone_number.clear()
|
||||
form_gen.input_phone_number = "17205290079"
|
||||
form_gen.input_phone_number.clear()
|
||||
|
||||
# right_number = drivers.find_element(By.XPATH,
|
||||
# '//*[@id="app"]/div/div[2]/section/div/div[2]/div[2]/div[1]/div/div/form/div[1]/div[1]/div/div/div/span[2]/span/span/span')
|
||||
assert form_gen.right_number.get_attribute("placeholder") == "请输入手机号" # 获取input框中的默认提示语
|
||||
assert form_gen.right_number.text == "0/11" # 这里有一个bug,由于电话号码都被clear清空了,后面的数据应该为0,而不是11,这里断言发现了一个bug,然后手动复现也是有这个bug的,然后就提bug了。
|
||||
# input_phone_number.send_keys("17205290078")
|
||||
form_gen.input_phone_number = "17205290078"
|
||||
form_gen.right_number.click()
|
||||
|
||||
assert form_gen.right_number.text == "11/11"
|
||||
assert form_gen.input_phone_number.get_attribute(
|
||||
"value") == "17205290078" # 对刚刚输入input框的str做断言,不能用text,因为是断言非用户输入的文本,后者是断言用户输入的文本,这里也可以在面试中如果被问道查看测试报告中的一些断言报错,就可以说这个。
|
||||
|
||||
# @pytest.mark.test1
|
||||
# def test_002_webdriver_inner_methods(self, drivers):
|
||||
# """
|
||||
# webdriver 是driver身上的方法
|
||||
# 浏览器名称
|
||||
# 当前url
|
||||
# 当前页面标题
|
||||
# 当前页面源码 : drivers.page_source
|
||||
# 窗口句柄
|
||||
# 当前窗口所有句柄,是一个list
|
||||
# """
|
||||
# print(drivers.name, drivers.current_url, drivers.title,drivers.current_window_handle, drivers.window_handles)
|
||||
# drivers.back()
|
||||
# drivers.forward()
|
||||
# drivers.refresh()
|
||||
# 退出当前标签页
|
||||
# drivers.close()
|
||||
# 退出谷歌浏览器
|
||||
# drivers.quit()
|
||||
|
||||
# def test_003_webelement_inner_methods(self, drivers):
|
||||
# button_login = drivers.find_elements(By.CLASS_NAME, "el-button")[0]
|
||||
# print(button_login.click(), button_login.text, button_login.is_displayed(), button_login.get_attribute('name'))
|
|
@ -1 +0,0 @@
|
|||
{"uuid": "ce0eeefd-2a2a-4018-a3b9-718cd422d8c6", "children": ["68fc0bc4-6ad8-49dc-924c-d3a871a19290"], "befores": [{"name": "drivers", "status": "passed", "start": 1692107307725, "stop": 1692107319283}], "afters": [{"name": "drivers::0", "status": "passed", "start": 1692107424127, "stop": 1692107428670}], "start": 1692107307725, "stop": 1692107428670}
|
|
@ -1 +0,0 @@
|
|||
{"uuid": "7c866e15-5cf4-401e-a2c7-0444227fcd47", "children": ["68fc0bc4-6ad8-49dc-924c-d3a871a19290"], "befores": [{"name": "open_baidu", "status": "passed", "start": 1692107319284, "stop": 1692107324782}], "afters": [{"name": "open_baidu::0", "status": "passed", "start": 1692107424126, "stop": 1692107424126}], "start": 1692107319284, "stop": 1692107424126}
|
|
@ -1 +0,0 @@
|
|||
{"name": "test_001[wzz-12345]", "status": "passed", "parameters": [{"name": "username", "value": "'wzz'"}, {"name": "password", "value": "'12345'"}], "start": 1692107324912, "stop": 1692107424124, "uuid": "68fc0bc4-6ad8-49dc-924c-d3a871a19290", "historyId": "d590c7043674851a28364ae332272855", "testCaseId": "75ce6b87312d044f17edfe42bfb0fde7", "fullName": "testcases.zhuifeng_tc.test_ddt_zhuifeng.TestSearch#test_001", "labels": [{"name": "tag", "value": "smoke"}, {"name": "parentSuite", "value": "testcases.zhuifeng_tc"}, {"name": "suite", "value": "test_ddt_zhuifeng"}, {"name": "subSuite", "value": "TestSearch"}, {"name": "host", "value": "LAPTOP-2RGLO47J"}, {"name": "thread", "value": "14440-MainThread"}, {"name": "framework", "value": "pytest"}, {"name": "language", "value": "cpython3"}, {"name": "package", "value": "testcases.zhuifeng_tc.test_ddt_zhuifeng"}]}
|
|
@ -1 +0,0 @@
|
|||
{"uuid": "7f2b1f3e-3d70-4378-8776-469aef9249b0", "befores": [{"name": "password", "status": "passed", "start": 1692107324783, "stop": 1692107324783}], "start": 1692107324783, "stop": 1692107424124}
|
|
@ -1 +0,0 @@
|
|||
{"uuid": "1bcd466c-4cff-414e-b378-8b136d4b2a10", "befores": [{"name": "username", "status": "passed", "start": 1692107324783, "stop": 1692107324783}], "start": 1692107324783, "stop": 1692107424126}
|
|
@ -43,7 +43,7 @@ class TestSearch:
|
|||
zhufeng.input_account = username
|
||||
zhufeng.input_password = password
|
||||
# zhufeng.log_in_button.click()
|
||||
zhufeng.image_code = image_identify(drivers, zhufeng.image, 'whole_pic.png', 'crop_pic.png')
|
||||
zhufeng.image_code = image_identify(drivers, zhufeng.image, '简单验证码.png', 'crop_pic.png')
|
||||
zhufeng.click_log_in_button
|
||||
time.sleep(3)
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@ import time
|
|||
import csv
|
||||
import threading
|
||||
|
||||
|
||||
"""
|
||||
test_pytest.fixture + 生成器yield 一起实现了和unittest的setup,teardown一样的前置启动,后置清理的装饰器
|
||||
"""
|
||||
|
@ -36,12 +35,15 @@ def open_baidu(drivers):
|
|||
yield
|
||||
print("后置")
|
||||
|
||||
|
||||
def read_csv_file(file_path):
|
||||
"""生成器方式去读取csv里面的数据来做数据驱动测试,yield关键字来控制一行一行的读取字典里面的内容(字典里面的数据是隐形的,还未产生,就和奶糖盒子一样的道理)"""
|
||||
with open(file_path, 'r', newline='') as file:
|
||||
reader = csv.DictReader(file) # 这是一个迭代器对象,把每次读取出来的数据都放到字典里面存起来,下面用一个for循环一次一次的去读取字典里面的数据,确保不会一次性将所有的数据读取到内存中。
|
||||
for row in reader: # 如过下面没有生成器,那么这里直接全部数据都遍历一遍,如果有生成器就会卡住,一个一个来,接收到next方法才会读取下一行。
|
||||
for row in reader: # 如过下面没有生成器,那么这里直接全部数据都遍历一遍,如果有生成器就会卡住,一个一个来,接收到next方法才会读取下一行。
|
||||
yield row['username'], row['password']
|
||||
|
||||
|
||||
@pytest.mark.smoke
|
||||
@pytest.mark.parametrize('username, password', read_csv_file(r'data/data.csv'))
|
||||
def test_001(drivers, username, password):
|
||||
|
@ -51,8 +53,3 @@ def test_001(drivers, username, password):
|
|||
# zhufeng.log_in_button.click()
|
||||
zhufeng.click_log_in_button
|
||||
# assert drivers.current_url == 'https://exam.wzzz.fun'
|
||||
|
||||
|
||||
# if __name__ == '__main__':
|
||||
# pytest.main(['--alluredir', './reports', 'vs', 'testcases/zhuifeng_tc/test_ddt_zhuifeng_csv_file.py'])
|
||||
|
||||
|
|
Loading…
Reference in New Issue