zhouhui.jiang

添加出口自动化

......@@ -727,6 +727,23 @@ const formatCurrency = (amount: number) => {
return '¥' + amount.toFixed(2)
}
// 格式化日期时间为后端需要的格式 (YYYY-MM-DD HH:MM:SS)
const formatDateTimeForBackend = (dateTimeString: string) => {
if (!dateTimeString) return ''
if (dateTimeString.includes('T')) {
// 将 YYYY-MM-DDTHH:MM 格式转换为 YYYY-MM-DD HH:MM:SS 格式
let formatted = dateTimeString.replace('T', ' ')
// 确保时间格式包含秒数,如果只有 HH:MM 则添加 :00
if (formatted.match(/\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/)) {
formatted += ':00'
}
return formatted
}
return dateTimeString
}
// 消息提示
const showMessage = (message: string, type: 'success' | 'error' | 'warning' = 'success') => {
console.log(`${type}: ${message}`)
......@@ -1048,11 +1065,7 @@ const calculateEditDeliveryItemTotal = (index: number) => {
const handleSubmitAdd = async () => {
try {
// 处理日期时间格式,将datetime-local格式转换为后端需要的格式
let formattedDeliveryDate = addFormData.deliveryDate
if (formattedDeliveryDate && formattedDeliveryDate.includes('T')) {
// 将 YYYY-MM-DDTHH:MM:SS 格式转换为 YYYY-MM-DD HH:MM:SS 格式
formattedDeliveryDate = formattedDeliveryDate.replace('T', ' ')
}
const formattedDeliveryDate = formatDateTimeForBackend(addFormData.deliveryDate)
// 构造新增出库的请求数据
const deliveryData: DeliveryAddReq = {
......@@ -1102,11 +1115,7 @@ const handleSubmitAdd = async () => {
const handleSubmitEdit = async () => {
try {
// 处理日期时间格式,将datetime-local格式转换为后端需要的格式
let formattedDeliveryDate = editFormData.deliveryDate
if (formattedDeliveryDate && formattedDeliveryDate.includes('T')) {
// 将 YYYY-MM-DDTHH:MM:SS 格式转换为 YYYY-MM-DD HH:MM:SS 格式
formattedDeliveryDate = formattedDeliveryDate.replace('T', ' ')
}
const formattedDeliveryDate = formatDateTimeForBackend(editFormData.deliveryDate)
// 构造编辑出库的请求数据
const deliveryData = {
......
"""
出库管理功能自动化测试
Python 3.7.8 兼容
"""
import time
from datetime import datetime
from base_test import BaseBrowserTest
class DeliveryManagementTest(BaseBrowserTest):
"""出库管理测试类"""
def setup_delivery_page(self):
"""设置出库管理页面"""
# 先登录
login_success = self.login('admin', 'password')
if not login_success:
raise Exception("登录失败,无法继续出库管理测试")
# 导航到出库管理页面
self.navigate_to(f'{self.base_url}/main/delivery')
# 等待页面加载
self.wait_for_element('.delivery-container')
self.wait_for_element('.search-section')
print("出库管理页面加载完成")
def test_delivery_search_by_delivery_no(self):
"""测试按出库单编号搜索"""
# 等待搜索表单加载
self.wait_for_element('input[placeholder="请输入出库单编号"]')
# 输入出库单编号进行搜索
test_delivery_no = "DL202501270001"
self.fill_input('input[placeholder="请输入出库单编号"]', test_delivery_no)
# 点击搜索按钮
self.click_element('button:has-text("🔍 搜索")')
# 等待搜索结果
self.page.wait_for_load_state('networkidle')
# 截图验证搜索结果
self.take_screenshot('delivery_search_by_delivery_no')
print("按出库单编号搜索测试通过")
def test_delivery_search_by_dealer(self):
"""测试按经销商搜索"""
# 等待搜索表单加载
self.wait_for_element('input[placeholder="请输入经销商编码"]')
# 输入经销商编码
self.fill_input('input[placeholder="请输入经销商编码"]', 'DL001')
# 输入经销商名称
self.fill_input('input[placeholder="请输入经销商名称"]', '北京经销商')
# 点击搜索按钮
self.click_element('button:has-text("🔍 搜索")')
# 等待搜索结果
self.page.wait_for_load_state('networkidle')
# 截图验证搜索结果
self.take_screenshot('delivery_search_by_dealer')
print("按经销商搜索测试通过")
def test_delivery_status_filter(self):
"""测试出库状态筛选"""
# 测试出库状态筛选
self.select_option('select:has(option[value="0"])', '0') # 未出库
# 点击搜索按钮
self.click_element('button:has-text("🔍 搜索")')
# 等待筛选结果
self.page.wait_for_load_state('networkidle')
# 截图验证筛选结果
self.take_screenshot('delivery_status_filter')
print("出库状态筛选测试通过")
def test_delivery_reset_search(self):
"""测试重置搜索"""
# 先填写一些搜索条件
self.fill_input('input[placeholder="请输入出库单编号"]', 'TEST-DL-001')
self.fill_input('input[placeholder="请输入经销商编码"]', 'TEST-DL')
self.select_option('select:has(option[value="1"])', '1') # 已出库
# 点击重置按钮
self.click_element('button:has-text("🔄 重置")')
# 等待重置完成
self.page.wait_for_load_state('networkidle')
# 验证搜索条件已清空
delivery_no_input = self.page.query_selector('input[placeholder="请输入出库单编号"]')
assert delivery_no_input.input_value() == '', "出库单编号输入框应该已清空"
dealer_code_input = self.page.query_selector('input[placeholder="请输入经销商编码"]')
assert dealer_code_input.input_value() == '', "经销商编码输入框应该已清空"
# 截图验证重置结果
self.take_screenshot('delivery_reset_search')
print("重置搜索测试通过")
def test_delivery_table_operations(self):
"""测试表格操作功能"""
# 等待表格加载
self.wait_for_element('.data-table')
# 测试全选功能
select_all_checkbox = self.page.query_selector('thead input[type="checkbox"]')
if select_all_checkbox:
select_all_checkbox.click()
self.page.wait_for_timeout(500) # 等待选择完成
# 截图验证全选结果
self.take_screenshot('delivery_table_select_all')
# 取消全选
select_all_checkbox.click()
self.page.wait_for_timeout(500)
# 测试单行选择
first_row_checkbox = self.page.query_selector('tbody tr:first-child input[type="checkbox"]')
if first_row_checkbox:
first_row_checkbox.click()
self.page.wait_for_timeout(500)
# 截图验证表格操作结果
self.take_screenshot('delivery_table_operations')
print("表格操作测试通过")
def test_add_delivery(self):
"""测试新增出库功能"""
# 等待操作按钮区域加载
self.wait_for_element('.action-section')
# 点击新增按钮
if self.is_element_visible('button:has-text("✨ 新增")'):
print("找到新增按钮,开始点击...")
# 确保页面稳定后再点击
self.page.wait_for_load_state('networkidle')
self.click_element('button:has-text("✨ 新增")')
self.page.wait_for_timeout(3000) # 等待弹窗打开
# 检查是否打开了新增出库的弹窗
if self.is_element_visible('.dialog-overlay'):
print("✅ 新增出库弹窗已打开")
# 等待弹窗完全加载
self.page.wait_for_timeout(1000)
self.take_screenshot('add_delivery_dialog_opened')
# 1. 填写出库单编号 - 使用最精确的选择器,只在弹窗内操作
delivery_no = 'TEST-OUT-0001'
delivery_no_selectors = [
'.dialog-content input.form-input[placeholder="请输入出库单编号"]', # 最精确:弹窗内的表单输入框
'.dialog-overlay input.form-input[placeholder="请输入出库单编号"]', # 弹窗覆盖层内的表单输入框
'.form-section input.form-input[placeholder="请输入出库单编号"]', # 表单区域内的输入框
'input.form-input[placeholder="请输入出库单编号"]:not(.search-input)' # 排除搜索框的表单输入框
]
delivery_no_filled = False
for selector in delivery_no_selectors:
if self.is_element_visible(selector):
print(f"找到出库单编号输入框: {selector}")
try:
# 先清空输入框
self.page.fill(selector, '')
self.page.wait_for_timeout(200)
# 填写出库单编号
self.page.fill(selector, delivery_no)
self.page.wait_for_timeout(300)
# 使用JavaScript直接设置值并触发Vue更新
self.page.evaluate(f"""
const input = document.querySelector('{selector}');
if (input) {{
input.value = '{delivery_no}';
input.dispatchEvent(new Event('input', {{ bubbles: true }}));
input.dispatchEvent(new Event('change', {{ bubbles: true }}));
input.dispatchEvent(new Event('blur', {{ bubbles: true }}));
}}
""")
self.page.wait_for_timeout(500)
# 验证是否填写成功
actual_value = self.page.input_value(selector)
if actual_value == delivery_no:
print(f"✅ 1. 填写出库单编号: {delivery_no}")
delivery_no_filled = True
break
except Exception as e:
print(f"填写出库单编号时出错: {e}")
if not delivery_no_filled:
print("❌ 未找到出库单编号输入框或填写失败")
# 2. 选择经销商名称 - 只在弹窗内操作
dealer_selectors = [
'.dialog-content select.form-select',
'.dialog-overlay select.form-select',
'.form-section select.form-select',
'select.form-select',
'.dialog-content select',
'.dialog-overlay select',
'.form-section select',
'select'
]
dealer_selected = False
for selector in dealer_selectors:
dealer_selects = self.page.locator(selector)
if dealer_selects.count() > 0:
# 尝试每个select元素
for i in range(dealer_selects.count()):
dealer_select = dealer_selects.nth(i)
if dealer_select.is_visible():
options = dealer_select.locator('option')
if options.count() > 1: # 除了"请选择"选项
try:
dealer_select.select_option(index=1)
print(f"✅ 2. 选择经销商名称(默认第一个)- 使用选择器: {selector}[{i}]")
dealer_selected = True
self.page.wait_for_timeout(500)
break
except Exception as e:
print(f"选择经销商时出错: {e}")
continue
if dealer_selected:
break
if not dealer_selected:
print("❌ 未找到经销商选择框或无法选择")
# 尝试查找所有select元素进行调试
all_selects = self.page.locator('select')
print(f"页面中找到 {all_selects.count()} 个select元素")
for i in range(all_selects.count()):
select = all_selects.nth(i)
if select.is_visible():
options = select.locator('option')
print(f"Select {i}: {options.count()} 个选项")
for j in range(min(options.count(), 3)): # 只显示前3个选项
option_text = options.nth(j).text_content()
print(f" 选项 {j}: {option_text}")
# 3. 填写关联订单编号 - 只在弹窗内操作
order_no = 'TEST-ORDER-0001'
order_no_selectors = [
'.dialog-content input[placeholder*="关联订单"]',
'.form-section input[placeholder*="关联订单"]',
'input[placeholder*="关联订单"]',
'input[name*="order"]',
'input[name*="订单"]'
]
order_no_filled = False
for selector in order_no_selectors:
if self.is_element_visible(selector):
try:
# 先清空输入框
self.page.fill(selector, '')
self.page.wait_for_timeout(200)
# 填写关联订单编号
self.page.fill(selector, order_no)
self.page.wait_for_timeout(300)
# 使用JavaScript直接设置值并触发Vue更新
self.page.evaluate(f"""
const input = document.querySelector('{selector}');
if (input) {{
input.value = '{order_no}';
input.dispatchEvent(new Event('input', {{ bubbles: true }}));
input.dispatchEvent(new Event('change', {{ bubbles: true }}));
input.dispatchEvent(new Event('blur', {{ bubbles: true }}));
}}
""")
self.page.wait_for_timeout(500)
# 验证是否填写成功
actual_value = self.page.input_value(selector)
if actual_value == order_no:
print(f"✅ 3. 填写关联订单编号: {order_no}")
order_no_filled = True
break
except Exception as e:
print(f"填写关联订单编号时出错: {e}")
if not order_no_filled:
print("❌ 未找到关联订单编号输入框或填写失败")
# 4. 填写出库日期 - 只在弹窗内操作
date_selectors = [
'.dialog-content input[type="datetime-local"]',
'.form-section input[type="datetime-local"]',
'input[type="datetime-local"]',
'.dialog-content input[type="date"]',
'.form-section input[type="date"]',
'input[type="date"]'
]
date_filled = False
for selector in date_selectors:
if self.is_element_visible(selector):
# 使用datetime-local格式:YYYY-MM-DDTHH:MM
now = datetime.now()
date_time_str = now.strftime('%Y-%m-%dT%H:%M')
self.page.fill(selector, date_time_str)
print(f"✅ 4. 填写出库日期: {date_time_str}")
date_filled = True
self.page.wait_for_timeout(500)
break
if not date_filled:
print("❌ 未找到出库日期输入框")
self.take_screenshot('add_delivery_form_filled')
# 5. 添加出库明细
if self.is_element_visible('button:has-text("+ 添加明细")'):
self.click_element('button:has-text("+ 添加明细")')
self.page.wait_for_timeout(2000) # 增加等待时间
print("✅ 5. 添加出库明细")
# 等待明细区域完全加载
self.page.wait_for_load_state('networkidle')
self.page.wait_for_timeout(1000)
# 5.1 选择产品名称 - 只在弹窗内操作
product_selectors = [
'.dialog-content .item-row select', # 明细行中的select
'.dialog-content .detail-row select', # 明细行中的select
'.dialog-content .form-row select', # 表单行中的select
'.dialog-content tbody select', # 表格体中的select
'.dialog-content select:not(:first-child)', # 除了第一个select
'select.form-select',
'select[name*="product"]',
'select[placeholder*="产品"]',
'.dialog-content select',
'.dialog-overlay select',
'.form-section select',
'select'
]
product_selected = False
for selector in product_selectors:
product_selects = self.page.locator(selector)
if product_selects.count() > 0:
# 尝试每个select元素
for i in range(product_selects.count()):
product_select = product_selects.nth(i)
if product_select.is_visible():
options = product_select.locator('option')
if options.count() > 1: # 除了"请选择"选项
try:
# 检查选项文本,找到产品相关的select
first_option = options.nth(0).text_content()
second_option = options.nth(1).text_content() if options.count() > 1 else ""
# 更精确的判断:排除经销商相关的select
if ('产品' in first_option or '请选择' in first_option) and '经销商' not in first_option:
product_select.select_option(index=1)
print(f"✅ 5.1 选择产品名称(第一个产品)- 使用选择器: {selector}[{i}]")
print(f" 选择的产品: {second_option}")
product_selected = True
self.page.wait_for_timeout(500)
break
except Exception as e:
print(f"选择产品时出错: {e}")
continue
if product_selected:
break
if not product_selected:
print("❌ 未找到产品选择框或无法选择")
# 尝试查找所有select元素进行调试
all_selects = self.page.locator('select')
print(f"添加明细后页面中找到 {all_selects.count()} 个select元素")
for i in range(all_selects.count()):
select = all_selects.nth(i)
if select.is_visible():
options = select.locator('option')
print(f"Select {i}: {options.count()} 个选项")
for j in range(min(options.count(), 3)): # 只显示前3个选项
option_text = options.nth(j).text_content()
print(f" 选项 {j}: {option_text}")
# 检查这个select是否已经被使用过(经销商选择)
try:
current_value = select.input_value()
if current_value:
print(f" Select {i} 当前值: {current_value} (可能已被使用)")
except:
pass
# 5.2 填写出库数量 - 只在弹窗内操作
quantity_selectors = [
'.dialog-content input[placeholder*="出库数量"]',
'.form-section input[placeholder*="出库数量"]',
'input[placeholder*="出库数量"]',
'.dialog-content input[placeholder*="数量"]',
'.form-section input[placeholder*="数量"]',
'input[placeholder*="数量"]'
]
quantity_filled = False
for selector in quantity_selectors:
if self.is_element_visible(selector):
self.page.fill(selector, '10')
print("✅ 5.2 填写出库数量: 10")
quantity_filled = True
self.page.wait_for_timeout(500)
break
if not quantity_filled:
print("❌ 未找到出库数量输入框")
# 5.3 填写出库单价 - 只在弹窗内操作
price_selectors = [
'.dialog-content input[placeholder*="出库单价"]',
'.form-section input[placeholder*="出库单价"]',
'input[placeholder*="出库单价"]',
'.dialog-content input[placeholder*="单价"]',
'.form-section input[placeholder*="单价"]',
'input[placeholder*="单价"]'
]
price_filled = False
for selector in price_selectors:
if self.is_element_visible(selector):
self.page.fill(selector, '100')
print("✅ 5.3 填写出库单价: 100")
price_filled = True
self.page.wait_for_timeout(500)
break
if not price_filled:
print("❌ 未找到出库单价输入框")
self.take_screenshot('add_delivery_with_items')
# 6. 点击确认保存出库
confirm_button_selectors = [
'button:has-text("确定")',
'button:has-text("保存")',
'button:has-text("提交")',
'button[type="submit"]',
'.submit-btn'
]
delivery_saved = False
for selector in confirm_button_selectors:
if self.is_element_visible(selector):
print(f"💾 6. 开始保存出库,点击按钮: {selector}")
self.click_element(selector)
# 等待保存处理
self.page.wait_for_timeout(3000)
# 检查是否有成功提示
page_text = self.page.text_content('body')
if '新增出库成功' in page_text or '保存成功' in page_text:
print("✅ 页面显示:新增出库成功")
has_success = True
else:
has_success = False
if has_success:
print("✅ 保存成功,等待弹窗关闭...")
# 成功提示出现后,等待弹窗关闭
self.page.wait_for_timeout(3000)
if not self.is_element_visible('.dialog-overlay'):
print("✅ 出库保存成功!弹窗已关闭")
self.take_screenshot('delivery_saved_successfully')
delivery_saved = True
else:
print("⚠️ 成功提示出现但弹窗未关闭,可能延迟关闭")
self.take_screenshot('delivery_save_success_but_dialog_open')
else:
# 没有明确的成功提示,检查弹窗状态
self.page.wait_for_timeout(3000)
# 检查保存结果
if not self.is_element_visible('.dialog-overlay'):
print("✅ 出库保存成功!弹窗已关闭")
self.take_screenshot('delivery_saved_successfully')
delivery_saved = True
else:
print("⚠️ 弹窗仍然存在,可能保存失败或需要更多时间")
# 再等待一下
self.page.wait_for_timeout(5000)
if not self.is_element_visible('.dialog-overlay'):
print("✅ 出库保存成功!(延迟确认)")
self.take_screenshot('delivery_saved_successfully_delayed')
delivery_saved = True
else:
print("❌ 出库保存失败,弹窗仍然存在")
self.take_screenshot('delivery_save_failed')
break
if not delivery_saved:
print("❌ 未找到确认按钮或保存失败")
# 如果保存失败,尝试关闭弹窗
cancel_button_selectors = [
'button:has-text("取消")',
'button:has-text("关闭")',
'.el-dialog__close'
]
for selector in cancel_button_selectors:
if self.is_element_visible(selector):
self.click_element(selector)
self.page.wait_for_timeout(1000)
print(f"✅ 点击取消按钮关闭弹窗: {selector}")
break
else:
print("❌ 新增出库弹窗未打开")
self.take_screenshot('add_delivery_dialog_not_opened')
else:
print("❌ 未找到新增按钮")
self.take_screenshot('add_button_not_found')
print("新增出库功能测试通过")
def test_edit_delivery(self):
"""测试编辑出库功能"""
# 等待数据表格加载
self.wait_for_element('.data-table')
# 查找 TEST-OUT-0001 出库单的编辑按钮
# 先尝试通过出库单编号找到对应的行
delivery_row = None
edit_button = None
# 方法1:通过表格行查找
table_rows = self.page.locator('.data-table tbody tr')
for i in range(table_rows.count()):
row = table_rows.nth(i)
row_text = row.text_content()
if 'TEST-OUT-0001' in row_text:
print(f"✅ 找到出库单 TEST-OUT-0001 在第 {i+1} 行")
delivery_row = row
# 在该行中查找编辑按钮
edit_button = row.locator('button:has-text("编辑")').first
if edit_button.count() > 0:
break
# 如果没有找到编辑按钮,尝试其他可能的按钮文本
edit_button = row.locator('button:has-text("✏️")').first
if edit_button.count() > 0:
break
edit_button = row.locator('button[title*="编辑"]').first
if edit_button.count() > 0:
break
if edit_button and edit_button.count() > 0:
print("找到编辑按钮,开始点击...")
# 确保页面稳定
self.page.wait_for_load_state('networkidle')
edit_button.click()
self.page.wait_for_timeout(3000) # 等待编辑弹窗打开
# 检查是否打开了编辑出库的弹窗
if self.is_element_visible('.dialog-overlay'):
print("✅ 编辑出库弹窗已打开")
self.take_screenshot('edit_delivery_dialog_opened')
# 查找仓库编码输入框并修改
warehouse_code_selectors = [
'.dialog-content input[placeholder*="仓库编码"]',
'.form-section input[placeholder*="仓库编码"]',
'input[placeholder*="仓库编码"]',
'input[name*="warehouse"]',
'input[name*="仓库"]'
]
warehouse_code_updated = False
for selector in warehouse_code_selectors:
if self.is_element_visible(selector):
# 获取当前仓库编码
current_warehouse_code = self.page.input_value(selector)
print(f"当前仓库编码: {current_warehouse_code}")
# 设置新的仓库编码
new_warehouse_code = 'WH001'
try:
# 清空并填写新的仓库编码
self.page.fill(selector, '')
self.page.wait_for_timeout(200)
self.page.fill(selector, new_warehouse_code)
self.page.wait_for_timeout(300)
# 使用JavaScript直接设置值并触发Vue更新
self.page.evaluate(f"""
const input = document.querySelector('{selector}');
if (input) {{
input.value = '{new_warehouse_code}';
input.dispatchEvent(new Event('input', {{ bubbles: true }}));
input.dispatchEvent(new Event('change', {{ bubbles: true }}));
input.dispatchEvent(new Event('blur', {{ bubbles: true }}));
}}
""")
self.page.wait_for_timeout(500)
# 验证是否修改成功
actual_value = self.page.input_value(selector)
if actual_value == new_warehouse_code:
print(f"✅ 仓库编码已更新: {current_warehouse_code} → {new_warehouse_code}")
warehouse_code_updated = True
break
except Exception as e:
print(f"修改仓库编码时出错: {e}")
if not warehouse_code_updated:
print("❌ 未找到仓库编码输入框或修改失败")
self.take_screenshot('edit_delivery_warehouse_updated')
# 点击保存按钮
save_button_selectors = [
'button:has-text("确定")',
'button:has-text("保存")',
'button:has-text("更新")',
'button:has-text("提交")',
'button[type="submit"]',
'.submit-btn'
]
delivery_saved = False
for selector in save_button_selectors:
if self.is_element_visible(selector):
print(f"💾 开始保存编辑,点击按钮: {selector}")
self.click_element(selector)
# 等待保存处理
self.page.wait_for_timeout(3000)
# 检查是否有成功提示
page_text = self.page.text_content('body')
if '更新成功' in page_text or '保存成功' in page_text or '修改成功' in page_text:
print("✅ 页面显示:出库更新成功")
has_success = True
else:
has_success = False
if has_success:
print("✅ 保存成功,等待弹窗关闭...")
# 成功提示出现后,等待弹窗关闭
self.page.wait_for_timeout(3000)
if not self.is_element_visible('.dialog-overlay'):
print("✅ 出库编辑保存成功!弹窗已关闭")
self.take_screenshot('delivery_edit_saved_successfully')
delivery_saved = True
else:
print("⚠️ 成功提示出现但弹窗未关闭,可能延迟关闭")
self.take_screenshot('delivery_edit_save_success_but_dialog_open')
else:
# 没有明确的成功提示,检查弹窗状态
self.page.wait_for_timeout(3000)
# 检查保存结果
if not self.is_element_visible('.dialog-overlay'):
print("✅ 出库编辑保存成功!弹窗已关闭")
self.take_screenshot('delivery_edit_saved_successfully')
delivery_saved = True
else:
print("⚠️ 弹窗仍然存在,可能保存失败或需要更多时间")
# 再等待一下
self.page.wait_for_timeout(5000)
if not self.is_element_visible('.dialog-overlay'):
print("✅ 出库编辑保存成功!(延迟确认)")
self.take_screenshot('delivery_edit_saved_successfully_delayed')
delivery_saved = True
else:
print("❌ 出库编辑保存失败,弹窗仍然存在")
self.take_screenshot('delivery_edit_save_failed')
break
if not delivery_saved:
print("❌ 未找到保存按钮或保存失败")
# 如果保存失败,尝试关闭弹窗
cancel_button_selectors = [
'button:has-text("取消")',
'button:has-text("关闭")',
'.el-dialog__close'
]
for selector in cancel_button_selectors:
if self.is_element_visible(selector):
self.click_element(selector)
self.page.wait_for_timeout(1000)
print(f"✅ 点击取消按钮关闭弹窗: {selector}")
break
else:
print("❌ 编辑出库弹窗未打开")
self.take_screenshot('edit_delivery_dialog_not_opened')
else:
print("❌ 未找到 TEST-OUT-0001 出库单或编辑按钮")
self.take_screenshot('edit_button_not_found')
print("编辑出库功能测试通过")
def test_view_delivery(self):
"""测试查看出库功能:打开详情弹窗并在2秒后关闭"""
# 确保表格加载完成
self.wait_for_element('.data-table')
# 查找包含 TEST-OUT-0001 的行
table_rows = self.page.locator('.data-table tbody tr')
view_button = None
for i in range(table_rows.count()):
row = table_rows.nth(i)
row_text = row.text_content()
if 'TEST-OUT-0001' in row_text:
print(f"✅ 找到出库单 TEST-OUT-0001 在第 {i+1} 行(用于查看)")
# 尝试不同的查看按钮选择器
candidates = [
'button:has-text("查看")',
'button:has-text("详情")',
'button[title*="查看"]',
'a:has-text("查看")',
'a[title*="查看"]',
'button:has-text("👁")',
]
for sel in candidates:
btn = row.locator(sel).first
if btn and btn.count() > 0:
view_button = btn
break
break
if view_button and view_button.count() > 0:
print("找到查看按钮,开始点击...")
self.page.wait_for_load_state('networkidle')
view_button.click()
self.page.wait_for_timeout(1500)
# 确认弹窗已打开
if self.is_element_visible('.dialog-overlay'):
print("✅ 查看出库弹窗已打开")
self.take_screenshot('view_delivery_dialog_opened')
# 等待2秒以模拟查看
self.page.wait_for_timeout(2000)
# 关闭弹窗(尝试多种关闭方式)
close_selectors = [
'button:has-text("关闭")',
'button:has-text("取消")',
'.el-dialog__close',
'.dialog-overlay .close-btn',
]
closed = False
for sel in close_selectors:
if self.is_element_visible(sel):
self.click_element(sel)
self.page.wait_for_timeout(1000)
if not self.is_element_visible('.dialog-overlay'):
closed = True
break
if not closed:
print("⚠️ 未找到关闭按钮,尝试按下ESC")
self.page.keyboard.press('Escape')
self.page.wait_for_timeout(1000)
if not self.is_element_visible('.dialog-overlay'):
print("✅ 查看弹窗已关闭")
self.take_screenshot('view_delivery_dialog_closed')
else:
print("❌ 查看弹窗关闭失败")
self.take_screenshot('view_delivery_dialog_close_failed')
else:
print("❌ 查看出库弹窗未打开")
self.take_screenshot('view_delivery_dialog_not_opened')
else:
print("❌ 未找到 TEST-OUT-0001 对应的查看按钮")
self.take_screenshot('view_button_not_found')
print("查看出库功能测试通过")
def run_delivery_management_tests():
"""运行出库管理测试"""
test_results = []
# 创建测试实例
test = DeliveryManagementTest(headless=False, slow_mo=500) # 非无头模式,慢速执行
# 先设置浏览器并登录一次
try:
test.setup_browser()
# 手动登录流程
print("开始登录...")
test.navigate_to(test.base_url)
test.fill_input('input[placeholder="请输入用户名"]', 'admin')
test.fill_input('input[placeholder="请输入密码"]', 'password')
test.click_element('button:has-text("登录")')
test.page.wait_for_timeout(5000)
# 检查登录是否成功
current_url = test.page.url
if 'dashboard' in current_url:
print("✅ 登录成功")
login_success = True
else:
print(f"❌ 登录失败,当前URL: {current_url}")
login_success = False
if not login_success:
print("❌ 登录失败,无法运行出库管理测试")
return []
# 导航到出库管理页面
test.navigate_to(f'{test.base_url}/main/delivery')
test.wait_for_element('.delivery-container', timeout=15000)
print("✅ 成功进入出库管理页面")
# 定义测试用例
test_cases = [
("按出库单编号搜索测试", test.test_delivery_search_by_delivery_no),
("按经销商搜索测试", test.test_delivery_search_by_dealer),
("出库状态筛选测试", test.test_delivery_status_filter),
("重置搜索测试", test.test_delivery_reset_search),
("表格操作测试", test.test_delivery_table_operations),
("新增出库功能测试", test.test_add_delivery),
("编辑出库功能测试", test.test_edit_delivery),
("查看出库功能测试", test.test_view_delivery),
]
# 运行所有测试(不重新创建浏览器)
results = []
for test_name, test_func in test_cases:
print(f"\n{'='*50}")
print(f"开始测试: {test_name}")
print(f"{'='*50}")
start_time = datetime.now()
result = {
'test_name': test_name,
'start_time': start_time.isoformat(),
'success': False,
'error': None,
'screenshots': [],
'duration': 0
}
try:
test_func()
result['success'] = True
print(f"✅ 测试通过: {test_name}")
except Exception as e:
result['error'] = str(e)
print(f"❌ 测试失败: {test_name}")
print(f"错误信息: {e}")
screenshot_path = test.take_screenshot(f'{test_name}_error')
result['screenshots'].append(screenshot_path)
finally:
end_time = datetime.now()
result['end_time'] = end_time.isoformat()
result['duration'] = (end_time - start_time).total_seconds()
print(f"测试耗时: {result['duration']:.2f}秒")
results.append(result)
return results
finally:
test.teardown_browser()
# 打印测试总结
print(f"\n{'='*60}")
print("出库管理测试总结")
print(f"{'='*60}")
passed = sum(1 for r in results if r['success'])
total = len(results)
for result in results:
status = "✅ 通过" if result['success'] else "❌ 失败"
print(f"{result['test_name']}: {status} ({result['duration']:.2f}s)")
if result['error']:
print(f" 错误: {result['error']}")
print(f"\n总计: {passed}/{total} 个测试通过")
if __name__ == '__main__':
run_delivery_management_tests()
......@@ -9,7 +9,9 @@ from datetime import datetime
from typing import List, Dict, Any
from test_login import run_login_tests
from test_order_management import run_order_management_tests
from test_order_management import run_order_management_tests, OrderManagementTest
from test_delivery_management import run_delivery_management_tests, DeliveryManagementTest
from base_test import BaseBrowserTest
class SimpleTestRunner:
......@@ -282,6 +284,150 @@ class SimpleTestRunner:
return report_file
def run_shared_browser_tests(self) -> List[Dict[str, Any]]:
"""运行共享浏览器实例的测试(订单管理 + 出库管理)"""
print("🚀 开始运行共享浏览器测试...")
print("=" * 60)
all_results = []
shared_browser = None
try:
# 创建共享的浏览器实例
shared_browser = BaseBrowserTest(headless=False, slow_mo=500)
shared_browser.setup_browser()
# 手动登录一次
print("开始登录...")
shared_browser.navigate_to(shared_browser.base_url)
shared_browser.fill_input('input[placeholder="请输入用户名"]', 'admin')
shared_browser.fill_input('input[placeholder="请输入密码"]', 'password')
shared_browser.click_element('button:has-text("登录")')
shared_browser.page.wait_for_timeout(5000)
# 检查登录是否成功
current_url = shared_browser.page.url
if 'dashboard' in current_url:
print("✅ 登录成功")
login_success = True
else:
print(f"❌ 登录失败,当前URL: {current_url}")
login_success = False
if not login_success:
print("❌ 登录失败,无法运行共享浏览器测试")
return []
# 1. 运行订单管理测试(使用共享浏览器)
print("\n📋 运行订单管理测试(共享浏览器)...")
try:
order_test = OrderManagementTest(headless=False, slow_mo=500)
# 直接使用已创建的浏览器实例
order_test.browser = shared_browser.browser
order_test.page = shared_browser.page
order_test.context = shared_browser.context
# 导航到订单管理页面
order_test.navigate_to(f'{order_test.base_url}/main/order')
order_test.wait_for_element('.order-container', timeout=15000)
print("✅ 成功进入订单管理页面")
# 运行订单管理测试用例
order_results = self._run_test_cases(order_test, [
("订单列表显示测试", order_test.test_order_list_display),
("按订单编号搜索测试", order_test.test_order_search_by_order_no),
("按经销商搜索测试", order_test.test_order_search_by_dealer),
("订单状态筛选测试", order_test.test_order_status_filter),
("重置搜索测试", order_test.test_reset_search),
("分页功能测试", order_test.test_pagination),
("表格操作测试", order_test.test_table_operations),
("新增订单功能测试", order_test.test_add_order),
("编辑订单功能测试", order_test.test_edit_order),
("查看订单功能测试", order_test.test_view_order),
])
all_results.extend(order_results)
print(f"✅ 订单管理测试完成,共 {len(order_results)} 个测试")
except Exception as e:
print(f"❌ 订单管理测试执行失败: {e}")
# 2. 运行出库管理测试(使用同一个浏览器实例)
print("\n📋 运行出库管理测试(共享浏览器)...")
try:
delivery_test = DeliveryManagementTest(headless=False, slow_mo=500)
# 直接使用已创建的浏览器实例
delivery_test.browser = shared_browser.browser
delivery_test.page = shared_browser.page
delivery_test.context = shared_browser.context
# 导航到出库管理页面
delivery_test.navigate_to(f'{delivery_test.base_url}/main/delivery')
delivery_test.wait_for_element('.delivery-container', timeout=15000)
print("✅ 成功进入出库管理页面")
# 运行出库管理测试用例
delivery_results = self._run_test_cases(delivery_test, [
("按出库单编号搜索测试", delivery_test.test_delivery_search_by_delivery_no),
("按经销商搜索测试", delivery_test.test_delivery_search_by_dealer),
("出库状态筛选测试", delivery_test.test_delivery_status_filter),
("重置搜索测试", delivery_test.test_delivery_reset_search),
("表格操作测试", delivery_test.test_delivery_table_operations),
("新增出库功能测试", delivery_test.test_add_delivery),
("编辑出库功能测试", delivery_test.test_edit_delivery),
("查看出库功能测试", delivery_test.test_view_delivery),
])
all_results.extend(delivery_results)
print(f"✅ 出库管理测试完成,共 {len(delivery_results)} 个测试")
except Exception as e:
print(f"❌ 出库管理测试执行失败: {e}")
finally:
# 最后关闭共享浏览器
if shared_browser:
shared_browser.teardown_browser()
print("✅ 共享浏览器已关闭")
return all_results
def _run_test_cases(self, test_instance, test_cases):
"""运行测试用例的通用方法"""
results = []
for test_name, test_func in test_cases:
print(f"\n{'='*50}")
print(f"开始测试: {test_name}")
print(f"{'='*50}")
start_time = datetime.now()
result = {
'test_name': test_name,
'start_time': start_time.isoformat(),
'success': False,
'error': None,
'screenshots': [],
'duration': 0
}
try:
test_func()
result['success'] = True
print(f"✅ 测试通过: {test_name}")
except Exception as e:
result['error'] = str(e)
print(f"❌ 测试失败: {test_name}")
print(f"错误信息: {e}")
screenshot_path = test_instance.take_screenshot(f'{test_name}_error')
result['screenshots'].append(screenshot_path)
finally:
end_time = datetime.now()
result['end_time'] = end_time.isoformat()
result['duration'] = (end_time - start_time).total_seconds()
print(f"测试耗时: {result['duration']:.2f}秒")
results.append(result)
return results
def run_all_tests(self) -> List[Dict[str, Any]]:
"""运行所有测试 - 顺序执行"""
print("🚀 开始运行浏览器自动化测试...")
......@@ -298,14 +444,14 @@ class SimpleTestRunner:
except Exception as e:
print(f"❌ 登录测试执行失败: {e}")
# 2. 运行订单管理测试
print("\n📋 运行订单管理测试...")
# 2. 运行共享浏览器测试(订单管理 + 出库管理)
print("\n📋 运行共享浏览器测试...")
try:
order_results = run_order_management_tests()
all_results.extend(order_results)
print(f"✅ 订单管理测试完成,共 {len(order_results)} 个测试")
shared_results = self.run_shared_browser_tests()
all_results.extend(shared_results)
print(f"✅ 共享浏览器测试完成,共 {len(shared_results)} 个测试")
except Exception as e:
print(f"❌ 订单管理测试执行失败: {e}")
print(f"❌ 共享浏览器测试执行失败: {e}")
# 生成报告
print("\n📊 生成测试报告...")
......