wms整体框架

This commit is contained in:
shiyinyi 2023-11-02 16:07:54 +08:00
parent bdb446b411
commit 2a2e35d1b7
53 changed files with 1172 additions and 163 deletions

View File

@ -25,6 +25,8 @@
pywinauto
图片验证码识别的库
ddddocr
颜色识别库
opencv-python
#### 使用说明

0
common/1.png Normal file
View File

BIN
common/crop_pic.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

33
common/ele_overlap.py Normal file
View File

@ -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() # 关闭浏览器驱动

View File

@ -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()

0
common/huadong.py Normal file
View File

View File

@ -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到180S通道饱和度的取值范围是0到255V通道亮度的取值范围是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)

View File

@ -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

19
common/image_verify.py Normal file
View File

@ -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"))

BIN
common/img.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

70
common/options_chrome.py Normal file
View File

@ -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
0DEFAULT使用默认日志记录级别
1VERBOSE输出详细的日志信息包括调试信息
2INFO输出一般的信息级别日志
3WARNING输出警告级别的日志
4ERROR输出错误级别的日志
5FATAL输出严重错误级别的日志
'''
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

34
common/pictures_same.py Normal file
View File

@ -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")

View File

@ -1,45 +0,0 @@
"""
-------------------------------------------------
File Name
Description :
Author : xiaobei
CreateDate
wechatxiaobei_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"))

14
common/slide.py Normal file
View File

@ -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()

View File

@ -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=?"))

View File

@ -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)

View File

@ -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):
"""日志目录"""

View File

@ -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的setupteardown一样的前置
管理数据库连接全局管理我们的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):
# """

View File

@ -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

View File

210
page/wms_pages/basePage.py Normal file
View File

@ -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

View File

View File

@ -0,0 +1,102 @@
from page.basePage import *
"""
-------------------------------------------------
File Name
Description :
Author : xiaobei
CreateDate
wechatxiaobei_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()

View File

@ -0,0 +1,28 @@
from page.basePage import *
"""
-------------------------------------------------
File Name
Description :
Author : xiaobei
CreateDate
wechatxiaobei_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()

View File

@ -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_*

View File

@ -3,6 +3,10 @@ pytest
allure-pytest
pytest-xdist
pytest-rerunfailures
pytest-ordering
pillow
pywinauto
ddddocr
ddddocr
pyyaml
requests
opencv-python

BIN
screenshots/blue.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
screenshots/crop_pic.png Normal file

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

View File

View File

View File

View File

View File

@ -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)

View File

@ -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的setupteardown一样的前置启动后置清理的装饰器
"""
@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'))

View File

@ -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}

View File

@ -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}

View File

@ -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"}]}

View File

@ -1 +0,0 @@
{"uuid": "7f2b1f3e-3d70-4378-8776-469aef9249b0", "befores": [{"name": "password", "status": "passed", "start": 1692107324783, "stop": 1692107324783}], "start": 1692107324783, "stop": 1692107424124}

View File

@ -1 +0,0 @@
{"uuid": "1bcd466c-4cff-414e-b378-8b136d4b2a10", "befores": [{"name": "username", "status": "passed", "start": 1692107324783, "stop": 1692107324783}], "start": 1692107324783, "stop": 1692107424126}

View File

@ -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)

View File

@ -23,7 +23,6 @@ import time
import csv
import threading
"""
test_pytest.fixture + 生成器yield 一起实现了和unittest的setupteardown一样的前置启动后置清理的装饰器
"""
@ -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'])