Skip to content

Commit 0cddc3f

Browse files
Add ZeroScript_AI_TestExecutor notebook
1 parent 17c0e13 commit 0cddc3f

File tree

1 file changed

+355
-0
lines changed

1 file changed

+355
-0
lines changed
Lines changed: 355 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,355 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {
6+
"id": "_T4g3t5sLoag"
7+
},
8+
"source": [
9+
"# ZeroScript: AI-Powered Browser Test Automation using PraisonAI Agent & OpenAI"
10+
]
11+
},
12+
{
13+
"cell_type": "markdown",
14+
"metadata": {
15+
"id": "O4PKfpalLsmn"
16+
},
17+
"source": [
18+
"# Description"
19+
]
20+
},
21+
{
22+
"cell_type": "markdown",
23+
"metadata": {
24+
"id": "CEG1pfumLysm"
25+
},
26+
"source": [
27+
"AI-powered browser testing using PraisonAI Agent and OpenAI. Executes YAML-defined test cases, captures screenshots, logs interactions, and generates JSON reports. Ideal for intelligent, automated UI testing.\n",
28+
"\n"
29+
]
30+
},
31+
{
32+
"cell_type": "markdown",
33+
"metadata": {
34+
"id": "lbgxOG4gL1Wf"
35+
},
36+
"source": [
37+
"[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/DhivyaBharathy-web/PraisonAI/blob/main/examples/cookbooks/ZeroScript_AI_TestExecutor.ipynb)\n"
38+
]
39+
},
40+
{
41+
"cell_type": "markdown",
42+
"metadata": {
43+
"id": "WCJqMUzXIndh"
44+
},
45+
"source": [
46+
"# Dependencies"
47+
]
48+
},
49+
{
50+
"cell_type": "code",
51+
"execution_count": 34,
52+
"metadata": {
53+
"id": "9AQhJ59cJPmR"
54+
},
55+
"outputs": [],
56+
"source": [
57+
"!pip install --quiet praisonaiagents browser-use python-dotenv pyyaml openai\n"
58+
]
59+
},
60+
{
61+
"cell_type": "markdown",
62+
"metadata": {
63+
"id": "QD-dF-6_It1z"
64+
},
65+
"source": [
66+
"# Environment Setup"
67+
]
68+
},
69+
{
70+
"cell_type": "code",
71+
"execution_count": 35,
72+
"metadata": {
73+
"colab": {
74+
"base_uri": "https://localhost:8080/"
75+
},
76+
"id": "QkRQDli4JhCV",
77+
"outputId": "4b8957ed-a37a-4b11-8585-3537a0437d40"
78+
},
79+
"outputs": [
80+
{
81+
"data": {
82+
"text/plain": [
83+
"True"
84+
]
85+
},
86+
"execution_count": 35,
87+
"metadata": {},
88+
"output_type": "execute_result"
89+
}
90+
],
91+
"source": [
92+
"import os\n",
93+
"from dotenv import load_dotenv\n",
94+
"\n",
95+
"os.environ[\"OPENAI_API_KEY\"] = \"Enter your key\" # replace with actual key\n",
96+
"load_dotenv()\n"
97+
]
98+
},
99+
{
100+
"cell_type": "markdown",
101+
"metadata": {
102+
"id": "ELuogWnrIw3o"
103+
},
104+
"source": [
105+
"# Create my_secrets.py"
106+
]
107+
},
108+
{
109+
"cell_type": "code",
110+
"execution_count": 36,
111+
"metadata": {
112+
"id": "sG6tO_v0Jm5N"
113+
},
114+
"outputs": [],
115+
"source": [
116+
"with open(\"my_secrets.py\", \"w\") as f:\n",
117+
" f.write('''sensitive_data = {\n",
118+
" \"username\": \"standard_user\",\n",
119+
" \"password\": \"secret_sauce\"\n",
120+
"}''')\n"
121+
]
122+
},
123+
{
124+
"cell_type": "markdown",
125+
"metadata": {
126+
"id": "rDB_viedIzRR"
127+
},
128+
"source": [
129+
"# Create views.py"
130+
]
131+
},
132+
{
133+
"cell_type": "code",
134+
"execution_count": 37,
135+
"metadata": {
136+
"id": "CtwcybdbJoV8"
137+
},
138+
"outputs": [],
139+
"source": [
140+
"with open(\"views.py\", \"w\") as f:\n",
141+
" f.write('''\n",
142+
"from pydantic import BaseModel\n",
143+
"\n",
144+
"class TestResult(BaseModel):\n",
145+
" status: str\n",
146+
" message: str = \"\"\n",
147+
"''')\n"
148+
]
149+
},
150+
{
151+
"cell_type": "markdown",
152+
"metadata": {
153+
"id": "YTRmBpTiI1kd"
154+
},
155+
"source": [
156+
"# Create agent.py"
157+
]
158+
},
159+
{
160+
"cell_type": "code",
161+
"execution_count": 38,
162+
"metadata": {
163+
"id": "zdJJGt6TJpvr"
164+
},
165+
"outputs": [],
166+
"source": [
167+
"with open(\"agent.py\", \"w\") as f:\n",
168+
" f.write('''\n",
169+
"import os\n",
170+
"from praisonaiagents import Agent\n",
171+
"from browser_use import Browser, BrowserConfig, Controller\n",
172+
"from browser_use.browser.context import BrowserContext, BrowserContextConfig\n",
173+
"from openai import OpenAI\n",
174+
"from views import TestResult\n",
175+
"from my_secrets import sensitive_data\n",
176+
"\n",
177+
"# Browser setup\n",
178+
"browser = Browser(config=BrowserConfig(headless=True))\n",
179+
"context_cfg = BrowserContextConfig(save_recording_path=\"data/recordings\")\n",
180+
"controller = Controller(output_model=TestResult)\n",
181+
"\n",
182+
"async def browser_use(task: str):\n",
183+
" context = BrowserContext(browser=browser, config=context_cfg)\n",
184+
" agent = Agent(\n",
185+
" task=task,\n",
186+
" llm=OpenAI(api_key=os.getenv(\"OPENAI_API_KEY\"), model=\"gpt-4\"),\n",
187+
" browser_context=context,\n",
188+
" sensitive_data=sensitive_data,\n",
189+
" controller=controller,\n",
190+
" save_conversation_path=\"data/conversations/convo\",\n",
191+
" extend_system_message=(\n",
192+
" \"You are a professional software tester. Execute browser test steps precisely.\"\n",
193+
" )\n",
194+
" )\n",
195+
" response = await agent.run()\n",
196+
" await context.close()\n",
197+
" return response\n",
198+
"''')\n"
199+
]
200+
},
201+
{
202+
"cell_type": "markdown",
203+
"metadata": {
204+
"id": "-LZtQIE3I4-_"
205+
},
206+
"source": [
207+
"# Create Sample Test YAML"
208+
]
209+
},
210+
{
211+
"cell_type": "code",
212+
"execution_count": 39,
213+
"metadata": {
214+
"colab": {
215+
"base_uri": "https://localhost:8080/"
216+
},
217+
"id": "l1OdXYI-JreK",
218+
"outputId": "62323fcd-c74f-498f-defc-2c170fa8983e"
219+
},
220+
"outputs": [
221+
{
222+
"data": {
223+
"text/plain": [
224+
"350"
225+
]
226+
},
227+
"execution_count": 39,
228+
"metadata": {},
229+
"output_type": "execute_result"
230+
}
231+
],
232+
"source": [
233+
"from pathlib import Path\n",
234+
"tests_dir = Path(\"tests\")\n",
235+
"tests_dir.mkdir(exist_ok=True)\n",
236+
"yaml_content = \"\"\"\n",
237+
"hooks:\n",
238+
" beforeEach: |\n",
239+
" Navigate to https://www.saucedemo.com\n",
240+
" afterEach: |\n",
241+
" Take screenshot\n",
242+
"\n",
243+
"tests:\n",
244+
" - id: \"login_test_001\"\n",
245+
" name: \"Valid Login Test\"\n",
246+
" instructions: |\n",
247+
" 1. Enter standard_user in username field\n",
248+
" 2. Enter secret_sauce in password field\n",
249+
" 3. Click login button\n",
250+
" 4. Verify page contains text \"Products\"\n",
251+
"\"\"\"\n",
252+
"(Path(\"tests/login_test.yml\")).write_text(yaml_content)\n"
253+
]
254+
},
255+
{
256+
"cell_type": "markdown",
257+
"metadata": {
258+
"id": "sUjy-7OdI7p_"
259+
},
260+
"source": [
261+
"# Run Tests"
262+
]
263+
},
264+
{
265+
"cell_type": "code",
266+
"execution_count": 40,
267+
"metadata": {
268+
"colab": {
269+
"base_uri": "https://localhost:8080/"
270+
},
271+
"id": "Agkiwh7xJtY3",
272+
"outputId": "759aa77c-fd65-49b8-b239-550588059478"
273+
},
274+
"outputs": [
275+
{
276+
"name": "stderr",
277+
"output_type": "stream",
278+
"text": [
279+
"Exception ignored in: <function BrowserSession.__del__ at 0x7e2f540fb100>\n",
280+
"Traceback (most recent call last):\n",
281+
" File \"/usr/local/lib/python3.11/dist-packages/browser_use/browser/session.py\", line 497, in __del__\n",
282+
" status = f'🪓 killing pid={self.browser_pid}...' if (self.browser_pid and owns_browser) else '☠️'\n",
283+
" ^^^^^^^^^^^^^^^^\n",
284+
" File \"/usr/local/lib/python3.11/dist-packages/pydantic/main.py\", line 991, in __getattr__\n",
285+
" raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')\n",
286+
"AttributeError: 'BrowserSession' object has no attribute 'browser_pid'\n"
287+
]
288+
},
289+
{
290+
"name": "stdout",
291+
"output_type": "stream",
292+
"text": [
293+
"✅ Report saved to data/reports/report_20250630_092319.json\n"
294+
]
295+
}
296+
],
297+
"source": [
298+
"import asyncio, yaml, json, base64, shutil\n",
299+
"from agent import browser_use, browser\n",
300+
"from pathlib import Path\n",
301+
"from datetime import datetime\n",
302+
"\n",
303+
"# Clean or create data dirs\n",
304+
"for sub in [\"recordings\", \"conversations\", \"screenshots\", \"reports\"]:\n",
305+
" d = Path(\"data\") / sub\n",
306+
" if d.exists(): shutil.rmtree(d)\n",
307+
" d.mkdir(parents=True, exist_ok=True)\n",
308+
"\n",
309+
"async def execute_test_file(path):\n",
310+
" cfg = yaml.safe_load(Path(path).read_text())\n",
311+
" hooks, results = cfg.get(\"hooks\", {}), []\n",
312+
" for t in cfg[\"tests\"]:\n",
313+
" task = f\"{hooks.get('beforeEach','')}\\n{t['instructions']}\\n{hooks.get('afterEach','')}\"\n",
314+
" res = {\"id\": t[\"id\"], \"name\": t[\"name\"]}\n",
315+
" try:\n",
316+
" r = await browser_use(task)\n",
317+
" imgs = r.screenshots()\n",
318+
" if imgs:\n",
319+
" out = Path(\"data/screenshots\") / f\"{t['id']}.png\"\n",
320+
" out.write_bytes(base64.b64decode(imgs[-1]))\n",
321+
" result_obj = r.final_result() if hasattr(r, \"final_result\") else str(r)\n",
322+
" res[\"result\"] = result_obj.dict() if hasattr(result_obj, \"dict\") else str(result_obj)\n",
323+
" except Exception as e:\n",
324+
" res[\"error\"] = str(e)\n",
325+
" results.append(res)\n",
326+
" return results\n",
327+
"\n",
328+
"async def main():\n",
329+
" all_results = []\n",
330+
" for file in Path(\"tests\").glob(\"*.yml\"):\n",
331+
" all_results.extend(await execute_test_file(str(file)))\n",
332+
" report = Path(\"data/reports\") / f\"report_{datetime.now():%Y%m%d_%H%M%S}.json\"\n",
333+
" report.write_text(json.dumps(all_results, indent=2))\n",
334+
" await browser.close()\n",
335+
" print(f\"✅ Report saved to {report}\")\n",
336+
"\n",
337+
"await main()\n"
338+
]
339+
}
340+
],
341+
"metadata": {
342+
"colab": {
343+
"provenance": []
344+
},
345+
"kernelspec": {
346+
"display_name": "Python 3",
347+
"name": "python3"
348+
},
349+
"language_info": {
350+
"name": "python"
351+
}
352+
},
353+
"nbformat": 4,
354+
"nbformat_minor": 0
355+
}

0 commit comments

Comments
 (0)