新增用例:新建疑修
This commit is contained in:
parent
6caa52586b
commit
b8716da798
|
@ -0,0 +1,28 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2023/11/22 14:48
|
||||
# @Author : floraachy
|
||||
# @File : issue_data
|
||||
# @Software: PyCharm
|
||||
# @Desc:
|
||||
|
||||
case_common = {
|
||||
"allure_epic": "GitLink",
|
||||
"allure_feature": "开源项目模块",
|
||||
}
|
||||
|
||||
# 登录成功
|
||||
new_issue_success = {
|
||||
"allure_story": "疑修",
|
||||
"cases":
|
||||
[
|
||||
{"title": "登录状态下,在测试仓库新建疑修",
|
||||
"run": True,
|
||||
"severity": "critical",
|
||||
"project_url": "${project_url}",
|
||||
"issue_title": "Auto Test ${generate_name()}",
|
||||
"issue_desc": "${generate_name()}",
|
||||
"issue_attach": "gitlinklogo2.png",
|
||||
|
||||
}
|
||||
]
|
||||
}
|
|
@ -17,10 +17,10 @@ login_pop_success = {
|
|||
"cases":
|
||||
[
|
||||
{"title": "弹窗登录: 正确用户名和密码登录成功",
|
||||
"user": "${login}",
|
||||
"password": "${password}",
|
||||
"run": True,
|
||||
"severity": "critical",
|
||||
"user": "${login}",
|
||||
"password": "${password}",
|
||||
"expected_url": "/explore",
|
||||
"expected_user": "${login}"
|
||||
}
|
||||
|
@ -32,10 +32,10 @@ login_page_success = {
|
|||
"cases":
|
||||
[
|
||||
{"title": "网页登录: 正确用户名和密码登录成功",
|
||||
"user": "${login}",
|
||||
"password": "${password}",
|
||||
"run": True,
|
||||
"severity": "critical",
|
||||
"user": "${login}",
|
||||
"password": "${password}",
|
||||
"expected_url": "/${login}",
|
||||
"expected_user": "${login}"
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
# 标准库导入
|
||||
import os
|
||||
from typing import Union
|
||||
# 第三方库导入
|
||||
import allure
|
||||
import time
|
||||
|
@ -114,6 +115,15 @@ class BasePage:
|
|||
logger.info(f"获取当前页面的路由:{url}")
|
||||
return url
|
||||
|
||||
@allure.step("获取当前网页标题")
|
||||
def get_page_title(self):
|
||||
"""
|
||||
获取网页标题
|
||||
"""
|
||||
page_title = self.driver.title
|
||||
logger.info(f"获取当前页面的网页标题:{page_title}")
|
||||
return page_title
|
||||
|
||||
@allure.step("____iframe切换- {reference}")
|
||||
def switch_to_frame(self, reference=None, timeout=10, poll=0.2):
|
||||
"""
|
||||
|
@ -332,32 +342,41 @@ class BasePage:
|
|||
allure.attach.file(source=file_path, attachment_type=allure.attachment_type.PNG)
|
||||
|
||||
@allure.step("____执行js脚本 - {js}")
|
||||
def execute_js(self, js):
|
||||
def execute_js(self, js, *args):
|
||||
"""
|
||||
执行javascript脚本
|
||||
js: 元组形式参数
|
||||
"""
|
||||
try:
|
||||
self.driver.execute_script(js)
|
||||
self.driver.execute_script(js, *args)
|
||||
logger.info(f"执行js脚本成功:{js}")
|
||||
except Exception as e:
|
||||
logger.error(f"执行js脚本失败:{js}, 报错:{e}")
|
||||
raise e
|
||||
|
||||
@allure.step("____使用pyautogui上传文件 - {files}")
|
||||
def upload_file_pyautogui(self, files: list):
|
||||
def upload_file_pyautogui(self, files: Union[str, list]):
|
||||
"""
|
||||
使用pyautogui来上传
|
||||
缺点:只能选择一个文件,路径中有中文会出问题。
|
||||
优点:跨平台。Linux, mac,windows都可以。
|
||||
安装:pip install pyautogui -i https://mirrors.aliyun.com/pypi/simple/
|
||||
:param files: 文件绝对路径,支持传数组
|
||||
:param files: 文件绝对路径, 支持传字符串或数组
|
||||
"""
|
||||
logger.info(f"使用pyautogui上传文件 - {files}")
|
||||
|
||||
for file in files:
|
||||
logger.info(f"使用pyautogui上传文件 - {file}")
|
||||
# 上传文件之前,确保打开选择文件框,确保鼠标聚焦在文件名框。增加一定等待时间,避免文件名键入错误
|
||||
time.sleep(2)
|
||||
|
||||
if isinstance(files, str):
|
||||
# 上传文件
|
||||
pyautogui.write(file)
|
||||
pyautogui.write(files)
|
||||
# 点击回车
|
||||
pyautogui.press("enter", 2)
|
||||
|
||||
if isinstance(files, list):
|
||||
for file in files:
|
||||
# 上传文件
|
||||
pyautogui.write(file)
|
||||
# 点击回车
|
||||
pyautogui.press("enter", 2)
|
||||
|
|
|
@ -318,7 +318,7 @@ class DataHandle:
|
|||
should_eval = 0
|
||||
for key, value in keys.items(): # 遍历字典替换
|
||||
obj = obj.replace(key, value[0])
|
||||
if not isinstance(source[value[1]], str):
|
||||
if source.get(value[1]) and not isinstance(source[value[1]], str):
|
||||
should_eval = 1
|
||||
if should_eval == 1:
|
||||
obj = self.eval_data(obj)
|
||||
|
@ -514,7 +514,8 @@ if __name__ == '__main__':
|
|||
print("-----------测试场景17---------------------")
|
||||
data_17 = {
|
||||
"winner_id": "${winner_id}",
|
||||
"user_id": "${user_id}"
|
||||
"user_id": "${user_id}",
|
||||
"time": "${generate_time}"
|
||||
}
|
||||
source = {
|
||||
"winner_id": "1,2,4",
|
||||
|
|
|
@ -51,7 +51,7 @@ class RunConfig:
|
|||
# 浏览器类型(不需要修改)
|
||||
driver_type = None
|
||||
# 浏览器驱动对象(不需要修改)
|
||||
drivers = None
|
||||
driver = None
|
||||
|
||||
# 失败重跑次数
|
||||
rerun = 0
|
||||
|
|
31
conftest.py
31
conftest.py
|
@ -39,22 +39,21 @@ def pytest_runtest_makereport(item, call):
|
|||
xfail = hasattr(report, "wasxfail")
|
||||
if (report.skipped and xfail) or (report.failed and not xfail):
|
||||
# 截图
|
||||
drivers = RunConfig.drivers
|
||||
if drivers:
|
||||
for driver in drivers:
|
||||
logger.debug(f"{driver}: 开始进行截图操作......")
|
||||
# 创建不同浏览器驱动保存截图的目录
|
||||
driver_dir = os.path.join(IMG_DIR, str(driver).split(".")[2])
|
||||
os.makedirs(driver_dir, exist_ok=True)
|
||||
parameters = item.callspec.params["case"]
|
||||
# logger.debug(f"测试用例参数:{type(parameters)} {parameters}")
|
||||
file_name = FakerData.remove_special_characters(
|
||||
target=parameters.get("title", "")) + "_" + datetime.now().strftime(
|
||||
"%Y-%m-%d %H_%M_%S") + ".png"
|
||||
BasePage(driver=driver).screenshot(path=driver_dir, filename=file_name)
|
||||
img_path = os.path.join(driver_dir, file_name)
|
||||
if img_path:
|
||||
allure_step(step_title="点击查看失败截图......", content=report.nodeid, source=img_path)
|
||||
if RunConfig.driver:
|
||||
driver = RunConfig.driver
|
||||
logger.debug(f"{driver}: 开始进行截图操作......")
|
||||
# 创建不同浏览器驱动保存截图的目录
|
||||
driver_dir = os.path.join(IMG_DIR, str(driver).split(".")[2])
|
||||
os.makedirs(driver_dir, exist_ok=True)
|
||||
parameters = item.callspec.params["case"]
|
||||
# logger.debug(f"测试用例参数:{type(parameters)} {parameters}")
|
||||
file_name = FakerData.remove_special_characters(
|
||||
target=parameters.get("title", "")) + "_" + datetime.now().strftime(
|
||||
"%Y-%m-%d %H_%M_%S") + ".png"
|
||||
BasePage(driver=driver).screenshot(path=driver_dir, filename=file_name)
|
||||
img_path = os.path.join(driver_dir, file_name)
|
||||
if img_path:
|
||||
allure_step(step_title="点击查看失败截图......", content=report.nodeid, source=img_path)
|
||||
|
||||
|
||||
def pytest_terminal_summary(terminalreporter, config):
|
||||
|
|
|
@ -18,6 +18,7 @@ class RepoCommonPage(BasePage):
|
|||
def open_site(self, host, project_url):
|
||||
"""访问项目详情页"""
|
||||
full_url = url_handle(host, project_url)
|
||||
print(f"这里的页面是什么:{full_url}")
|
||||
self.visit(full_url)
|
||||
return full_url
|
||||
|
||||
|
|
|
@ -7,39 +7,59 @@
|
|||
|
||||
# 标准库导入
|
||||
import os
|
||||
import time
|
||||
# 第三方库导入
|
||||
from selenium.webdriver.common.by import By
|
||||
# 本地应用/模块导入
|
||||
from case_utils.base_page import BasePage
|
||||
from case_utils.allure_handle import allure_step
|
||||
from case_utils.tools import url_handle
|
||||
|
||||
|
||||
class RepoIssuePage(BasePage):
|
||||
def open_site(self, host):
|
||||
"""
|
||||
访问仓库疑修页面
|
||||
"""
|
||||
full_url = url_handle(host, "/issues")
|
||||
self.visit(full_url)
|
||||
|
||||
def click_create_issue_button(self):
|
||||
"""
|
||||
点击"创建疑修"按钮
|
||||
"""
|
||||
self.click((By.XPATH, "//a[text()='创建疑修']"))
|
||||
time.sleep(3)
|
||||
|
||||
def input_issue_title(self, issue_title: str):
|
||||
"""
|
||||
输入疑修标题
|
||||
"""
|
||||
self.input((By.ID, "subject"), text=issue_title)
|
||||
time.sleep(1)
|
||||
|
||||
def input_issue_desc(self, issue_desc: str):
|
||||
"""
|
||||
输入疑修内容
|
||||
"""
|
||||
elem = self.driver.find_element(By.XPATH, "//textarea/following::div[contains(@class, 'CodeMirror-wrap')]")
|
||||
self.execute_js('''([elem, content]) => elem.CodeMirror.setValue(content);''',
|
||||
[elem, issue_desc])
|
||||
self.execute_js("arguments[0].CodeMirror.setValue(arguments[1]);", elem, issue_desc)
|
||||
time.sleep(1)
|
||||
|
||||
def upload_issue_attach(self, issue_file):
|
||||
"""
|
||||
上传疑修附件
|
||||
"""
|
||||
self.click(locator=(By.XPATH, "//p[text()='拖动文件或点击此处上传']/parent::div/preceding-sibling::input"))
|
||||
time.sleep(1)
|
||||
self.upload_file_pyautogui(files=issue_file)
|
||||
time.sleep(1)
|
||||
|
||||
def submit_issue(self):
|
||||
"""
|
||||
点击"创建"按钮,提交表单校验,进行疑修创建
|
||||
"""
|
||||
self.click((By.XPATH, "//span[text()='创 建']/parent::button"))
|
||||
time.sleep(3)
|
||||
|
||||
def get_issue_success_text(self):
|
||||
"""
|
||||
|
@ -53,16 +73,16 @@ class RepoIssuePage(BasePage):
|
|||
"""
|
||||
return self.get_text((By.XPATH, "//div[@class='detailtitle']/div/p"))
|
||||
|
||||
def check_issue_desc(self):
|
||||
def get_issue_desc(self):
|
||||
"""
|
||||
获取易修内容
|
||||
"""
|
||||
return self.get_text((By.XPATH, "//div[@class='descPanel']/div/p"))
|
||||
|
||||
def get_issue_attachments(self, files):
|
||||
def get_issue_attachments(self):
|
||||
"""
|
||||
检查易修附件
|
||||
"""
|
||||
actual_issue_files = self.get_all_elements_text(
|
||||
locator="//div[contains(@class, 'attachment-list-div')]//span[1]")
|
||||
return [os.path.basename(file_path) for file_path in files]
|
||||
(By.XPATH, "//div[contains(@class, 'attachment-list-div')]//span[1]"))
|
||||
return [os.path.basename(file_path) for file_path in actual_issue_files]
|
||||
|
|
2
run.py
2
run.py
|
@ -93,7 +93,7 @@ if __name__ == '__main__':
|
|||
help="是否生成allure html report,支持如下类型:yes, no")
|
||||
parser.add_argument("-env", default="test", help="输入运行环境:test 或 live")
|
||||
parser.add_argument("-m", default=None, help="选择需要运行的用例:python.ini配置的名称")
|
||||
parser.add_argument("-driver", default="chrome",
|
||||
parser.add_argument("-driver", default="chrome-headless",
|
||||
help="浏览器驱动类型配置,支持如下类型:chrome, chrome-headless, firefox, firefox-headless, edge")
|
||||
args = parser.parse_args()
|
||||
run(**vars(args))
|
||||
|
|
|
@ -28,7 +28,7 @@ def case_handle(request):
|
|||
|
||||
# 处理用例数据
|
||||
case = data_handle(obj=case, source=GLOBAL_VARS)
|
||||
logger.trace(f"当前执行的用例数据:{case}, {type(case)}")
|
||||
logger.debug(f"当前执行的用例数据:{case}, {type(case)}")
|
||||
# 添加用例标题作为allure中显示的用例标题
|
||||
allure_title(case.get("title", ""))
|
||||
|
||||
|
|
|
@ -8,56 +8,21 @@
|
|||
# 标准库导入
|
||||
# 第三方库导入
|
||||
import pytest
|
||||
from requests.utils import dict_from_cookiejar
|
||||
from loguru import logger
|
||||
# 本地应用/模块导入
|
||||
from config.global_vars import GLOBAL_VARS
|
||||
from case_utils.base_request import BaseRequest
|
||||
from page_objects.login_page import LoginPage
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def login_api():
|
||||
@pytest.fixture(scope="function")
|
||||
def login_driver(request):
|
||||
"""
|
||||
获取登录的cookie
|
||||
登录
|
||||
:return:
|
||||
"""
|
||||
driver = request.getfixturevalue("init_driver")
|
||||
host = GLOBAL_VARS.get("host")
|
||||
login = GLOBAL_VARS.get('login')
|
||||
password = GLOBAL_VARS.get('password')
|
||||
# 兼容一下host后面多一个斜线的情况
|
||||
if host[-1] == "/":
|
||||
host = host[:len(host) - 1]
|
||||
req_data = {
|
||||
"url": host + "/api/accounts/login.json",
|
||||
"method": "POST",
|
||||
"request_type": "json",
|
||||
"headers": {"Content-Type": "application/json; charset=utf-8;"},
|
||||
"payload": {"login": login, "password": password, "autologin": 1}
|
||||
}
|
||||
# 请求登录接口
|
||||
try:
|
||||
res = BaseRequest.send_request(req_data=req_data)
|
||||
res.raise_for_status()
|
||||
# 将cookies转成字典
|
||||
cookies = dict_from_cookiejar(res.cookies)
|
||||
logger.debug(f"获取用户:{login}登录的cookies成功:{type(cookies)} || {cookies}")
|
||||
yield cookies, res.json()
|
||||
except Exception as e:
|
||||
GLOBAL_VARS["login_cookie"] = None
|
||||
logger.error(f"获取用户:{login}登录的cookies失败:{e}")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def write_login_cookies(request, login_api):
|
||||
driver = request.getfixturevalue("init_driver")
|
||||
# 遍历 cookies 字典并添加到 WebDriver 中
|
||||
login_cookies = login_api[0]
|
||||
for name, value in login_cookies.items():
|
||||
"""
|
||||
add_cookie() 方法是 WebDriver 的方法,用于向浏览器添加 cookie。正确的方法调用应该只有两个参数:name 和 value
|
||||
"""
|
||||
driver.add_cookie({"name": name, "value": value})
|
||||
|
||||
# 刷新页面
|
||||
driver.refresh()
|
||||
LoginPage(driver).open_site(host)
|
||||
LoginPage(driver).login_on_page(login=login, password=password)
|
||||
yield driver
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
# @Desc:
|
||||
# 标准库导入
|
||||
# 第三方库导入
|
||||
import time
|
||||
import pytest
|
||||
import allure
|
||||
# 本地应用/模块导入
|
||||
|
@ -16,8 +15,7 @@ from page_objects.home_page import HomePage
|
|||
from page_objects.projects.create_export_project_page import CreateExportProjectPage
|
||||
from page_objects.projects.repo_common_page import RepoCommonPage
|
||||
from page_objects.projects.repo_setting_page import RepoSettingPage
|
||||
from case_utils.data_handle import data_handle
|
||||
from case_utils.allure_handle import allure_title, allure_step
|
||||
from case_utils.allure_handle import allure_step
|
||||
from case_data.create_project_flow_data import *
|
||||
from loguru import logger
|
||||
|
||||
|
@ -33,7 +31,7 @@ class TestCreateProject:
|
|||
@allure.story(new_project_success["allure_story"])
|
||||
@pytest.mark.parametrize("case", new_project_success["cases"],
|
||||
ids=["{}".format(case["title"]) for case in new_project_success["cases"]])
|
||||
def test_new_project(self, case, write_login_cookies):
|
||||
def test_new_project(self, case, login_driver):
|
||||
"""
|
||||
名称:登录状态下,通过右上角导航栏点击新建>新建项目按钮, 新建个人公有项目
|
||||
前提条件:
|
||||
|
@ -63,8 +61,8 @@ class TestCreateProject:
|
|||
# 处理URL
|
||||
host = GLOBAL_VARS.get("host", "")
|
||||
|
||||
with allure.step("保持登录态"):
|
||||
driver = write_login_cookies
|
||||
with allure.step("输入用户名和密码进行登录"):
|
||||
driver = login_driver
|
||||
|
||||
with allure.step("进入首页"):
|
||||
HomePage(driver).open_site(host)
|
||||
|
@ -123,5 +121,5 @@ class TestCreateProject:
|
|||
@allure.story(export_project_success["allure_story"])
|
||||
@pytest.mark.parametrize("case", export_project_success["cases"],
|
||||
ids=["{}".format(case["title"]) for case in export_project_success["cases"]])
|
||||
def test_export_project(self, init_driver, case, request):
|
||||
def test_export_project(self, case, login_driver):
|
||||
pass
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# @Time : 2023/11/22 14:45
|
||||
# @Author : floraachy
|
||||
# @File : test_issue
|
||||
# @Software: PyCharm
|
||||
# @Desc:
|
||||
|
||||
# 标准库导入
|
||||
import os
|
||||
# 第三方库导入
|
||||
import pytest
|
||||
import allure
|
||||
# 本地应用/模块导入
|
||||
from config.global_vars import GLOBAL_VARS
|
||||
from config.path_config import ATTACH_DIR
|
||||
from page_objects.projects.repo_issue_page import RepoIssuePage
|
||||
from page_objects.projects.repo_common_page import RepoCommonPage
|
||||
from case_utils.allure_handle import allure_step
|
||||
from case_data.issue_data import *
|
||||
from loguru import logger
|
||||
|
||||
|
||||
@pytest.mark.issue
|
||||
@allure.epic(case_common["allure_epic"])
|
||||
@allure.feature(case_common["allure_feature"])
|
||||
class TestProjectIssue:
|
||||
"""
|
||||
疑修的测试用例
|
||||
"""
|
||||
|
||||
@allure.story(new_issue_success["allure_story"])
|
||||
@pytest.mark.parametrize("case", new_issue_success["cases"],
|
||||
ids=["{}".format(case["title"]) for case in new_issue_success["cases"]])
|
||||
def test_new_issue(self, case, login_driver):
|
||||
"""
|
||||
名称:登录状态下,在测试仓库新建疑修
|
||||
前提条件:
|
||||
1. 进入测试仓库
|
||||
2. 写入登录cookies,并刷新页面
|
||||
步骤:(新建疑修)
|
||||
1. 点击"疑修(Issue)"导航栏
|
||||
2. 点击"创建疑修"按钮
|
||||
3. 进入页面:${project_url}/issues/new
|
||||
4. 输入疑修标题,内容
|
||||
5. 上传疑修附件
|
||||
6. 点击"创建"按钮
|
||||
7. 疑修创建成功,提示: 任务创建成功!
|
||||
断言:
|
||||
1)页面进入疑修详情页, 检查网页标题,疑修标题,内容及附件
|
||||
"""
|
||||
|
||||
# 处理URL
|
||||
host = GLOBAL_VARS.get("host", "")
|
||||
|
||||
with allure.step("输入用户名和密码进行登录"):
|
||||
driver = login_driver
|
||||
|
||||
issue_title = case["issue_title"]
|
||||
issue_desc = case["issue_desc"]
|
||||
issue_file = os.path.join(ATTACH_DIR, case["issue_attach"])
|
||||
|
||||
with allure.step("访问项目详情页, 点击'疑修(Issue)'导航栏"):
|
||||
RepoCommonPage(driver).open_site(host=host, project_url=case["project_url"])
|
||||
RepoCommonPage(driver).click_repo_nav_button(nav="疑修(Issue)")
|
||||
|
||||
# ------------------------- 新建疑修-------------------------
|
||||
with allure.step("点击'创建疑修'按钮"):
|
||||
RepoIssuePage(driver).click_create_issue_button()
|
||||
|
||||
with allure.step("断言--> 进入页面:${project_url}/issues/new"):
|
||||
assert f"{case['project_url']}/issues/new" in driver.current_url
|
||||
|
||||
with allure.step(
|
||||
"输入疑修标题,内容, 上传疑修附件, 点击'创建'按钮"):
|
||||
RepoIssuePage(driver).input_issue_title(issue_title=issue_title)
|
||||
RepoIssuePage(driver).input_issue_desc(issue_desc=issue_desc)
|
||||
RepoIssuePage(driver).upload_issue_attach(issue_file=issue_file)
|
||||
RepoIssuePage(driver).submit_issue()
|
||||
|
||||
with allure.step("断言--> 疑修创建成功,提示: 任务创建成功!"):
|
||||
assert "任务创建成功!" == RepoIssuePage(driver).get_issue_success_text()
|
||||
|
||||
with allure.step("断言--> 页面进入疑修详情页, 检查网页标题,疑修标题,内容及附件"):
|
||||
expect = issue_title
|
||||
actual = RepoIssuePage(driver).get_page_title()
|
||||
allure_step(step_title=f"断言--> 网页标题包含疑修标题 预期: {expect} 实际:{actual}")
|
||||
assert expect in actual
|
||||
|
||||
expect = issue_title
|
||||
actual = RepoIssuePage(driver).get_issue_title()
|
||||
allure_step(step_title=f"断言--> 疑修标题与输入的一致 预期: {expect} 实际:{actual}")
|
||||
assert expect in actual
|
||||
|
||||
expect = issue_desc
|
||||
actual = RepoIssuePage(driver).get_issue_desc()
|
||||
allure_step(step_title=f"断言--> 疑修内容与输入的一致 预期: {expect} 实际:{actual}")
|
||||
assert expect in actual
|
||||
|
||||
expect = os.path.basename(issue_file)
|
||||
if isinstance(expect, str):
|
||||
actual = RepoIssuePage(driver).get_issue_attachments()[0]
|
||||
allure_step(step_title=f"断言--> 疑修内容与输入的一致 预期: {expect} 实际:{actual}")
|
||||
assert expect in actual
|
||||
elif isinstance(expect, list):
|
||||
actual = RepoIssuePage(driver).get_issue_attachments()
|
||||
allure_step(step_title=f"断言--> 疑修内容与输入的一致 预期: {expect} 实际:{actual}")
|
||||
assert expect in actual
|
Loading…
Reference in New Issue