Skip to content

Commit 5bd1068

Browse files
author
Shriyansh Agnihotri
committed
Adding Accessbility testing feature to browser agent
1 parent d1ebdb1 commit 5bd1068

19 files changed

+325
-399
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,15 @@ To cut down on some of the DOM noise, we use the **DOM Accessibility Tree** rath
545545

546546
The distillation process is a work in progress. We look to refine this process and condense the DOM further, aiming to make interactions faster, cost-effective, and more accurate.
547547

548+
---
549+
### Non-Functional Capabilities
550+
551+
#### Security Testing via Nuclei
552+
Hercules integrates with **Nuclei** to automate vulnerability scanning directly from Gherkin test cases, identifying issues like **misconfigurations, OWASP Top 10 vulnerabilities**, and API flaws. Security reports are generated alongside testing outputs for seamless CI/CD integration.
553+
554+
#### Accessibility Testing
555+
Hercules supports **WCAG 2.0, 2.1, and 2.2** at **A, AA, and AAA levels**, enabling accessibility testing to ensure compliance with global standards. It identifies accessibility issues early, helping build inclusive and user-friendly applications.
556+
548557
---
549558

550559
## 🔬 Testing and Evaluation: QEvals
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Feature: Check accessibility for brokerage calculator on Zerodha website
2+
3+
# This feature tests the brokerage calculator, and contract notes on Zerodha website
4+
5+
Scenario Outline: Check calculations on brokerage and SEBI charges
6+
Given the user is on "https://zerodha.com/brokerage-calculator#tab-equities"
7+
then validate the page for accessibility.
8+
Then there should not be any issues.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
tests="1" errors="0" failures="1" skipped="0"

tests/test_features/accessibility/test_data.txt

Whitespace-only changes.

testzeus_hercules/__main__.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44

55
from junit2htmlreport.runner import run as prepare_html
66
from testzeus_hercules.config import (
7+
get_dont_close_browser,
78
get_input_gherkin_file_path,
89
get_junit_xml_base_path,
10+
get_proof_path,
911
get_source_log_folder_path,
1012
set_default_test_id,
11-
get_dont_close_browser,
1213
)
1314
from testzeus_hercules.core.runner import SingleCommandInputRunner
1415
from testzeus_hercules.telemetry import EventData, EventType, add_event
@@ -48,9 +49,7 @@ def sequential_process() -> None:
4849
feature_file_name = os.path.basename(input_gherkin_file_path)
4950

5051
result_of_tests = []
51-
final_result_file_name = (
52-
f"{get_junit_xml_base_path()}/{feature_file_name}_result.xml"
53-
)
52+
final_result_file_name = f"{get_junit_xml_base_path()}/{feature_file_name}_result.xml"
5453
add_event(EventType.RUN, EventData(detail="Total Runs: " + str(len(list_of_feats))))
5554
for feat in list_of_feats:
5655
file_path = feat["output_file"]
@@ -97,21 +96,19 @@ def sequential_process() -> None:
9796
scenario,
9897
feature_file_path=file_path,
9998
output_file_path="",
99+
proofs_path=get_proof_path(runner.browser_manager.stake_id),
100100
proofs_screenshot_path=runner.browser_manager._screenshots_dir,
101101
proofs_video_path=runner.browser_manager.get_latest_video_path(),
102102
network_logs_path=runner.browser_manager.request_response_log_file,
103103
logs_path=get_source_log_folder_path(stake_id),
104-
planner_thoughts_path=get_source_log_folder_path(stake_id)
105-
+ "/chat_messages.json",
104+
planner_thoughts_path=get_source_log_folder_path(stake_id) + "/chat_messages.json",
106105
)
107106
)
108107
JUnitXMLGenerator.merge_junit_xml(result_of_tests, final_result_file_name)
109108
logger.info(f"Results published in junitxml file: {final_result_file_name}")
110109

111110
# building html from junitxml
112-
final_result_html_file_name = (
113-
f"{get_junit_xml_base_path()}/{feature_file_name}_result.html"
114-
)
111+
final_result_html_file_name = f"{get_junit_xml_base_path()}/{feature_file_name}_result.html"
115112
prepare_html([final_result_file_name, final_result_html_file_name])
116113
logger.info(f"Results published in html file: {final_result_html_file_name}")
117114

testzeus_hercules/config.py

Lines changed: 12 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,9 @@
1616

1717

1818
def arguments() -> None:
19-
parser = argparse.ArgumentParser(
20-
description="Hercules: The World's First Open-Source AI Agent for End-to-End Testing"
21-
)
22-
parser.add_argument(
23-
"--input-file", type=str, help="Path to the input file.", required=False
24-
)
25-
parser.add_argument(
26-
"--output-path", type=str, help="Path to the output directory.", required=False
27-
)
19+
parser = argparse.ArgumentParser(description="Hercules: The World's First Open-Source AI Agent for End-to-End Testing")
20+
parser.add_argument("--input-file", type=str, help="Path to the input file.", required=False)
21+
parser.add_argument("--output-path", type=str, help="Path to the output directory.", required=False)
2822
parser.add_argument(
2923
"--test-data-path",
3024
type=str,
@@ -82,17 +76,11 @@ def arguments() -> None:
8276
agents_llm_config_file_ref_key = os.environ.get("AGENTS_LLM_CONFIG_FILE_REF_KEY")
8377

8478

85-
if (llm_model_name and llm_model_api_key) and (
86-
agents_llm_config_file or agents_llm_config_file_ref_key
87-
):
88-
logger.error(
89-
"Provide either LLM_MODEL_NAME and LLM_MODEL_API_KEY together, or AGENTS_LLM_CONFIG_FILE and AGENTS_LLM_CONFIG_FILE_REF_KEY together, not both."
90-
)
79+
if (llm_model_name and llm_model_api_key) and (agents_llm_config_file or agents_llm_config_file_ref_key):
80+
logger.error("Provide either LLM_MODEL_NAME and LLM_MODEL_API_KEY together, or AGENTS_LLM_CONFIG_FILE and AGENTS_LLM_CONFIG_FILE_REF_KEY together, not both.")
9181
exit(1)
9282

93-
if (not llm_model_name or not llm_model_api_key) and (
94-
not agents_llm_config_file or not agents_llm_config_file_ref_key
95-
):
83+
if (not llm_model_name or not llm_model_api_key) and (not agents_llm_config_file or not agents_llm_config_file_ref_key):
9684
logger.error(
9785
"Either LLM_MODEL_NAME and LLM_MODEL_API_KEY must be set together, or AGENTS_LLM_CONFIG_FILE and AGENTS_LLM_CONFIG_FILE_REF_KEY must be set together. user --llm-model and --llm-model-api-key in hercules command"
9886
)
@@ -109,18 +97,12 @@ def arguments() -> None:
10997
PROJECT_TEMP_PATH = os.path.join(PROJECT_ROOT, "temp")
11098
PROJECT_TEST_ROOT = os.path.join(PROJECT_ROOT, "test")
11199

112-
INPUT_GHERKIN_FILE_PATH = os.environ.get("INPUT_GHERKIN_FILE_PATH") or os.path.join(
113-
PROJECT_ROOT, "input/test.feature"
114-
)
100+
INPUT_GHERKIN_FILE_PATH = os.environ.get("INPUT_GHERKIN_FILE_PATH") or os.path.join(PROJECT_ROOT, "input/test.feature")
115101
TMP_GHERKIN_PATH = os.path.join(PROJECT_ROOT, "gherkin_files")
116-
JUNIT_XML_BASE_PATH = os.environ.get("JUNIT_XML_BASE_PATH") or os.path.join(
117-
PROJECT_ROOT, "output"
118-
)
102+
JUNIT_XML_BASE_PATH = os.environ.get("JUNIT_XML_BASE_PATH") or os.path.join(PROJECT_ROOT, "output")
119103

120104
SOURCE_LOG_FOLDER_PATH = os.path.join(PROJECT_ROOT, "log_files")
121-
TEST_DATA_PATH = os.environ.get("TEST_DATA_PATH") or os.path.join(
122-
PROJECT_ROOT, "test_data"
123-
)
105+
TEST_DATA_PATH = os.environ.get("TEST_DATA_PATH") or os.path.join(PROJECT_ROOT, "test_data")
124106
SCREEN_SHOT_PATH = os.path.join(PROJECT_ROOT, "proofs")
125107

126108
if "HF_HOME" not in os.environ:
@@ -217,9 +199,7 @@ def get_input_gherkin_file_path() -> str:
217199
base_path = os.path.dirname(INPUT_GHERKIN_FILE_PATH)
218200
if not os.path.exists(base_path):
219201
os.makedirs(base_path)
220-
logger.info(
221-
f"Created INPUT_GHERKIN_FILE_PATH folder at: {INPUT_GHERKIN_FILE_PATH}"
222-
)
202+
logger.info(f"Created INPUT_GHERKIN_FILE_PATH folder at: {INPUT_GHERKIN_FILE_PATH}")
223203
return INPUT_GHERKIN_FILE_PATH
224204

225205

@@ -263,9 +243,7 @@ def get_source_log_folder_path(test_id: Optional[str] = None) -> str:
263243
source_log_folder_path = os.path.join(SOURCE_LOG_FOLDER_PATH, test_id)
264244
if not os.path.exists(source_log_folder_path):
265245
os.makedirs(source_log_folder_path)
266-
logger.info(
267-
f"Created source_log_folder_path folder at: {source_log_folder_path}"
268-
)
246+
logger.info(f"Created source_log_folder_path folder at: {source_log_folder_path}")
269247
return source_log_folder_path
270248

271249

@@ -328,6 +306,4 @@ def get_project_temp_path(test_id: Optional[str] = None) -> str:
328306
"BROWSER_TYPE": get_browser_type(),
329307
"CAPTURE_NETWORK": should_capture_network(),
330308
}
331-
add_event(
332-
EventType.CONFIG, EventData(detail="General Config", additional_data=config_brief)
333-
)
309+
add_event(EventType.CONFIG, EventData(detail="General Config", additional_data=config_brief))

testzeus_hercules/core/agents/browser_nav_agent.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from testzeus_hercules.core.memory.state_handler import *
1111
from testzeus_hercules.core.memory.static_ltm import get_user_ltm
1212
from testzeus_hercules.core.prompts import LLM_PROMPTS
13+
from testzeus_hercules.core.tools.accessibility_calls import *
1314
from testzeus_hercules.core.tools.captcha_solver import *
1415
from testzeus_hercules.core.tools.click_using_selector import click as click_element
1516
from testzeus_hercules.core.tools.dropdown_using_selector import *

0 commit comments

Comments
 (0)