Skip to content

Commit dd7f642

Browse files
committed
feat: enhance test case management and update README
- Add automatic case indexing (1: CASE_NAME format) to fix duplicate names - Add HuggingFace Spaces and community links to README
1 parent 2bdb7f9 commit dd7f642

File tree

6 files changed

+74
-25
lines changed

6 files changed

+74
-25
lines changed

README.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
1-
# WebQA Agent
1+
<h1 align="center">WebQA Agent</h1>
22

33
<!-- badges -->
4-
<p align="left">
4+
<p align="center">
55
<a href="https://github.com/MigoXLab/webqa-agent/blob/main/LICENSE"><img src="https://img.shields.io/github/license/MigoXLab/webqa-agent" alt="License"></a>
66
<a href="https://github.com/MigoXLab/webqa-agent/stargazers"><img src="https://img.shields.io/github/stars/MigoXLab/webqa-agent" alt="GitHub stars"></a>
77
<a href="https://github.com/MigoXLab/webqa-agent/network/members"><img src="https://img.shields.io/github/forks/MigoXLab/webqa-agent" alt="GitHub forks"></a>
88
<a href="https://github.com/MigoXLab/webqa-agent/issues"><img src="https://img.shields.io/github/issues/MigoXLab/webqa-agent" alt="GitHub issues"></a>
99
<a href="https://deepwiki.com/MigoXLab/webqa-agent"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a>
1010
</p>
1111

12-
[English](README.md) · [简体中文](README_zh-CN.md)
12+
<p align="center">
13+
Try Demo 🤗<a href="https://huggingface.co/spaces/mmmay0722/WebQA-Agent">HuggingFace</a> | 🚀<a href="https://modelscope.cn/studios/mmmmei22/WebQA-Agent/summary">ModelScope</a><br>
14+
Join us on 🎮<a href="https://discord.gg/K5TtkVcx">Discord</a> | 💬<a href="https://aicarrier.feishu.cn/docx/NRNXdIirXoSQEHxhaqjchUfenzd">WeChat</a>
15+
</p>
16+
17+
<p align="center"><a href="README.md">English</a> · <a href="README_zh-CN.md">简体中文</a></p>
1318

14-
**WebQA Agent** is an autonomous web agent that audits performance, functionality, and UX for any web product.
19+
<p align="center">🤖 <strong>WebQA Agent</strong> is an autonomous web browser agent that audits performance, functionality & UX for engineers and vibe-coding creators. ✨</p>
1520

1621
## 🚀 Core Features
1722

@@ -101,7 +106,9 @@ python webqa-agent.py
101106

102107
## Online Demo
103108

104-
Experience online: [WebQA-Agent on ModelScope](https://modelscope.cn/studios/mmmmei22/WebQA-Agent/summary)
109+
🚀 **Try WebQA Agent Online:**
110+
- **Hugging Face Spaces**: [WebQA-Agent on Hugging Face](https://huggingface.co/spaces/mmmay0722/WebQA-Agent)
111+
- **ModelScope Studio**: [WebQA-Agent on ModelScope](https://modelscope.cn/studios/mmmmei22/WebQA-Agent/summary)
105112

106113
## Usage
107114

README_zh-CN.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
1-
# WebQA Agent
1+
<h1 align="center">WebQA Agent</h1>
22

33
<!-- badges -->
4-
<p align="left">
4+
<p align="center">
55
<a href="https://github.com/MigoXLab/webqa-agent/blob/main/LICENSE"><img src="https://img.shields.io/github/license/MigoXLab/webqa-agent" alt="License"></a>
66
<a href="https://github.com/MigoXLab/webqa-agent/stargazers"><img src="https://img.shields.io/github/stars/MigoXLab/webqa-agent" alt="GitHub stars"></a>
77
<a href="https://github.com/MigoXLab/webqa-agent/network/members"><img src="https://img.shields.io/github/forks/MigoXLab/webqa-agent" alt="GitHub forks"></a>
88
<a href="https://github.com/MigoXLab/webqa-agent/issues"><img src="https://img.shields.io/github/issues/MigoXLab/webqa-agent" alt="GitHub issues"></a>
99
<a href="https://deepwiki.com/MigoXLab/webqa-agent"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a>
1010
</p>
1111

12-
[English](README.md) · [简体中文](README_zh-CN.md)
12+
<p align="center">
13+
体验Demo 🤗<a href="https://huggingface.co/spaces/mmmay0722/WebQA-Agent">HuggingFace</a> | 🚀<a href="https://modelscope.cn/studios/mmmmei22/WebQA-Agent/summary">ModelScope</a><br>
14+
加入我们 🎮<a href="https://discord.gg/K5TtkVcx">Discord</a> | 💬<a href="https://aicarrier.feishu.cn/docx/NRNXdIirXoSQEHxhaqjchUfenzd">微信群</a>
15+
</p>
16+
17+
<p align="center"><a href="README.md">English</a> · <a href="README_zh-CN.md">简体中文</a></p>
1318

14-
**WebQA Agent** 是全自动网页评估测试 Agent,一键诊断性能、安全、功能与交互体验
19+
<p align="center">🤖 <strong>WebQA Agent</strong> 是全自动网页评估测试 Agent,一键完成性能、功能与交互体验的测试评估 ✨</p>
1520

1621
## 🚀 核心特性
1722

@@ -104,7 +109,9 @@ python webqa-agent.py
104109

105110
## 在线演示
106111

107-
进入ModelScope体验:[WebQA-Agent on ModelScope](https://modelscope.cn/studios/mmmmei22/WebQA-Agent/summary)
112+
🚀 **在线体验 WebQA Agent:**
113+
- **Hugging Face Spaces**: [WebQA-Agent on Hugging Face](https://huggingface.co/spaces/mmmay0722/WebQA-Agent)
114+
- **ModelScope Studio**: [WebQA-Agent on ModelScope](https://modelscope.cn/studios/mmmmei22/WebQA-Agent/summary)
108115

109116
## 使用说明
110117

app_gradio/demo_gradio.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,16 @@ def create_config_dict(
157157
report_language: str = "zh-CN"
158158
) -> Dict[str, Any]:
159159
"""Create configuration dictionary"""
160+
161+
final_business_objectives = business_objectives.strip()
162+
default_constraint = get_text(report_language, "config.default_business_objectives")
163+
164+
if final_business_objectives:
165+
separator = ","
166+
final_business_objectives = f"{final_business_objectives}{separator}{default_constraint}"
167+
else:
168+
final_business_objectives = default_constraint
169+
160170
config = {
161171
"target": {
162172
"url": url,
@@ -166,7 +176,7 @@ def create_config_dict(
166176
"function_test": {
167177
"enabled": function_test_enabled,
168178
"type": function_test_type,
169-
"business_objectives": business_objectives
179+
"business_objectives": final_business_objectives
170180
},
171181
"ux_test": {
172182
"enabled": ux_test_enabled
@@ -321,10 +331,6 @@ def submit_test(
321331
if not any([function_test_enabled, ux_test_enabled, performance_test_enabled, security_test_enabled]):
322332
return get_text(interface_language, "messages.error_no_tests"), "", False
323333

324-
# If function test is enabled but no business objectives set
325-
if function_test_enabled and function_test_type == "ai" and not business_objectives.strip():
326-
return get_text(interface_language, "messages.error_no_business_objectives"), "", False
327-
328334
# Validate LLM configuration
329335
valid, msg = validate_llm_config(api_key, base_url, model, interface_language)
330336
if not valid:
@@ -357,6 +363,7 @@ def submit_test(
357363
"tests": {
358364
"function": function_test_enabled,
359365
"function_type": function_test_type,
366+
"business_objectives": business_objectives,
360367
"ux": ux_test_enabled,
361368
},
362369
"submitted_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
@@ -630,6 +637,15 @@ def create_gradio_interface(language: str = "zh-CN"):
630637
.fixed-width-table td:nth-child(6),
631638
.content-wrapper .gradio-dataframe th:nth-child(6),
632639
.content-wrapper .gradio-dataframe td:nth-child(6) {
640+
width: auto !important;
641+
max-width: none !important;
642+
min-width: 200px !important;
643+
text-align: left !important;
644+
}
645+
.fixed-width-table th:nth-child(7),
646+
.fixed-width-table td:nth-child(7),
647+
.content-wrapper .gradio-dataframe th:nth-child(7),
648+
.content-wrapper .gradio-dataframe td:nth-child(7) {
633649
width: auto !important;
634650
max-width: none !important;
635651
min-width: 70px !important;
@@ -866,12 +882,21 @@ def submit_and_expand(*args):
866882
def get_history_rows(lang):
867883
rows = []
868884
for item in reversed(submission_history[-100:]):
885+
business_objectives = item["tests"].get("business_objectives", "")
886+
function_type = item["tests"]["function_type"]
887+
888+
if function_type == "ai" and business_objectives:
889+
business_display = business_objectives[:30] + "..." if len(business_objectives) > 30 else business_objectives
890+
else:
891+
business_display = "-"
892+
869893
rows.append([
870894
item["submitted_at"],
871895
item["task_id"],
872896
item["url"],
873897
"✅" if item["tests"]["function"] else "-",
874898
item["tests"]["function_type"],
899+
business_display,
875900
"✅" if item["tests"]["ux"] else "-"
876901
])
877902
return rows

app_gradio/gradio_i18n.json

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@
2929
"function_test_type": "功能测试类型",
3030
"function_test_type_info": "default: 遍历测试,覆盖可点击元素和所有链接\n ai: 基于视觉模型的智能测试,能够模拟真实用户行为、理解业务上下文,验证网页功能。",
3131
"business_objectives": "AI功能测试业务目标",
32-
"business_objectives_placeholder": "测试对话功能,生成2个用例",
33-
"business_objectives_info": "ai: 定制不同场景,精准发现复杂功能问题",
32+
"business_objectives_placeholder": "测试对话功能",
33+
"business_objectives_info": "ai: 定制不同场景,精准发现复杂功能问题。留空将使用默认设置(生成1个测试用例,每个用例包含6个步骤以内)",
34+
"default_business_objectives": "生成1个测试用例,每个用例包含6个步骤以内",
3435
"ux_test": "用户体验测试",
3536
"performance_test": "性能测试",
3637
"performance_test_info": "目前在 ModelScope 版本不可用;请前往 GitHub 体验",
@@ -54,7 +55,7 @@
5455
},
5556
"history": {
5657
"title": "提交记录",
57-
"headers": ["提交时间", "任务ID", "URL", "功能测试", "类型", "UX测试"],
58+
"headers": ["提交时间", "任务ID", "URL", "功能测试", "类型", "业务目标", "UX测试"],
5859
"refresh_btn": "🔄 刷新历史记录"
5960
},
6061
"messages": {
@@ -118,8 +119,9 @@
118119
"function_test_type": "Function Test Type",
119120
"function_test_type_info": "default: Traverse clickable elements & links.\n ai: Vision-model intelligent test simulating users & validating functionality.",
120121
"business_objectives": "AI Function Test Business Objectives",
121-
"business_objectives_placeholder": "Test chat functionality, generate 2 test cases",
122-
"business_objectives_info": "ai: Customize different scenarios, accurately find complex functional issues",
122+
"business_objectives_placeholder": "Test chat functionality",
123+
"business_objectives_info": "ai: Customize different scenarios, accurately find complex functional issues. Leave blank to use default settings (generate 1 test case with no more than 6 steps per case)",
124+
"default_business_objectives": "Generate 1 test case with no more than 6 steps per case",
123125
"ux_test": "User Experience Test",
124126
"performance_test": "Performance Test",
125127
"performance_test_info": "Currently unavailable in HuggingFace version; please visit GitHub for experience",
@@ -143,7 +145,7 @@
143145
},
144146
"history": {
145147
"title": "Submission Records",
146-
"headers": ["Submit Time", "Task ID", "URL", "Function Test", "Type", "UX Test"],
148+
"headers": ["Submit Time", "Task ID", "URL", "Function Test", "Type", "Business Objectives", "UX Test"],
147149
"refresh_btn": "🔄 Refresh History"
148150
},
149151
"messages": {

docs/images/webqa.svg

Lines changed: 1 addition & 1 deletion
Loading

webqa_agent/testers/function_tester.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ async def _generate_plan(self, system_prompt: str, prompt: str, browser_screensh
335335
raise ValueError(f"Invalid JSON response: {str(je)}")
336336

337337
if not plan_json.get("actions"):
338+
logging.error(f"No valid actions found in plan: {test_plan}")
338339
raise ValueError("No valid actions found in plan")
339340

340341
return plan_json
@@ -477,8 +478,14 @@ def start_case(self, case_name: str, case_data: Optional[Dict[str, Any]] = None)
477478
)
478479
self.finish_case("interrupted", "Case was interrupted by new case start")
479480

481+
# Calculate case index (1-based)
482+
case_index = len(self.all_cases_data) + 1
483+
formatted_case_name = f"{case_index}: {case_name}"
484+
480485
self.current_case_data = {
481-
"name": case_name,
486+
"name": formatted_case_name,
487+
"original_name": case_name, # Keep original name for reference
488+
"case_index": case_index,
482489
"start_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
483490
"case_info": case_data or {},
484491
"steps": [],
@@ -494,7 +501,7 @@ def start_case(self, case_name: str, case_data: Optional[Dict[str, Any]] = None)
494501
}
495502
self.current_case_steps = []
496503
self.step_counter = 0 # Reset step counter
497-
logging.debug(f"Started tracking case: {case_name} (step counter reset)")
504+
logging.debug(f"Started tracking case: {formatted_case_name} (step counter reset)")
498505

499506
def add_step_data(self, step_data: Dict[str, Any], step_type: str = "action"):
500507
"""Add step data to current case."""
@@ -547,6 +554,7 @@ def finish_case(self, final_status: str = "completed", final_summary: Optional[s
547554
return
548555

549556
case_name = self.current_case_data.get("name", "Unknown")
557+
original_name = self.current_case_data.get("original_name", case_name)
550558
steps_count = len(self.current_case_steps)
551559

552560
# Get monitoring data
@@ -624,7 +632,7 @@ def generate_runner_format_report(self, test_id: str = None, test_name: str = No
624632
total_steps = 0
625633
for i, case in enumerate(self.all_cases_data):
626634
case_steps = case.get("steps", [])
627-
case_name = case.get("name", f"Case_{i}")
635+
case_name = case.get("name", f"Case_{i + 1}") # Use 1-based indexing as fallback
628636
total_steps += len(case_steps)
629637
logging.debug(
630638
f"Report validation - Case '{case_name}': {len(case_steps)} steps, status: {case.get('status', 'unknown')}"

0 commit comments

Comments
 (0)