Skip to main content

test_chatgpt_and_google/
test_chatgpt_and_google.rs

1use anyhow::Result;
2use headless_engine::browser::tab::BrowserTab;
3use headless_engine::network::fingerprint::DeviceProfile;
4use serde_json::json;
5use std::fs;
6use std::path::Path;
7
8#[tokio::main]
9async fn main() -> Result<()> {
10    println!("================================================================================");
11    println!(">>> TEST SUITE: CHATGPT.COM (AGENTIC MODE) & GOOGLE.COM (AI MODE, AI OVERVIEW, NORMAL SEARCH)");
12    println!("================================================================================\n");
13
14    let artifact_dir = Path::new(
15        r"C:\Users\abhis\.gemini\antigravity-ide\brain\c08da294-7846-44b1-9403-559e0d23ce0f",
16    );
17    let evidence_dir = Path::new("evidence");
18    fs::create_dir_all(evidence_dir)?;
19    if !artifact_dir.exists() {
20        let _ = fs::create_dir_all(artifact_dir);
21    }
22
23    // =========================================================================
24    // PART 1: CHATGPT.COM (AGENTIC MODE TESTING)
25    // =========================================================================
26    println!("--------------------------------------------------------------------------------");
27    println!(">>> [1/4] TESTING CHATGPT.COM — AGENTIC MODE & INTERACTIVE ACTION TREE");
28    println!("--------------------------------------------------------------------------------");
29
30    let mut gpt_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
31    let gpt_url = "https://chatgpt.com/";
32    println!(
33        "  [Step 1.1] Navigating with Stealth Anti-Detection to {}...",
34        gpt_url
35    );
36    let gpt_nav = gpt_tab.navigate(gpt_url).await?;
37    println!("  -> Landed Status:    {}", gpt_nav.status);
38    println!("  -> Page Title:       {}", gpt_nav.page_title);
39    println!("  -> CAPTCHA Detected: {}", gpt_nav.is_captcha_detected);
40    println!("  -> HTML Payload:     {} bytes", gpt_nav.html_bytes);
41
42    // Agentic Observation & Action Tree
43    println!("  [Step 1.2] Extracting Agent Action Map (Interactive Elements)...");
44    let gpt_obs = gpt_tab.observe().expect("Expected ChatGPT observation");
45    println!(
46        "  -> Total Interactive Elements Indexed: {}",
47        gpt_obs.interactive_elements.len()
48    );
49
50    // Print sample of action tree
51    println!("\n  >>> CHATGPT AGENT ACTION MAP (First 10 Interactive Elements):");
52    for el in gpt_obs.interactive_elements.iter().take(10) {
53        println!("    {}", el.to_agent_string());
54    }
55
56    // Agentic Action: Attempt to find prompt input or interactive button
57    let input_target = gpt_obs
58        .interactive_elements
59        .iter()
60        .find(|e| {
61            e.is_input
62                || e.tag == "textarea"
63                || e.placeholder.to_lowercase().contains("message")
64                || e.placeholder.to_lowercase().contains("ask")
65                || e.selector.contains("prompt")
66        })
67        .cloned();
68
69    let button_target = gpt_obs
70        .interactive_elements
71        .iter()
72        .find(|e| e.tag == "button" || e.role == "button")
73        .cloned();
74
75    let mut action_executed = "None".to_string();
76    if let Some(target) = &input_target {
77        println!(
78            "\n  [Step 1.3: Agent Act] Agent typing into input element [{}] (Selector: {})...",
79            target.index, target.selector
80        );
81        let type_res = gpt_tab
82            .act_type(
83                &target.index.to_string(),
84                "Explain quantum computing in one sentence",
85            )
86            .await?;
87        println!("  -> Type Action Result: {}", type_res);
88        action_executed = format!("Type into element [{}] ({})", target.index, target.selector);
89    } else if let Some(target) = &button_target {
90        println!(
91            "\n  [Step 1.3: Agent Act] Agent inspecting interactive button [{}] (Text: \"{}\")...",
92            target.index, target.text
93        );
94        action_executed = format!("Inspect/Focus button [{}] ({})", target.index, target.text);
95    }
96
97    // Capture ChatGPT Screenshot
98    println!("  [Step 1.4] Capturing ChatGPT Visual Screenshot...");
99    let gpt_shot = gpt_tab
100        .screenshot_async()
101        .await
102        .expect("Expected screenshot");
103    println!(
104        "  -> Screenshot PNG Size: {} bytes ({}x{})",
105        gpt_shot.png_bytes.len(),
106        gpt_shot.width,
107        gpt_shot.height
108    );
109
110    if !gpt_shot.png_bytes.is_empty() {
111        fs::write(
112            evidence_dir.join("chatgpt_screenshot.png"),
113            &gpt_shot.png_bytes,
114        )?;
115        fs::write(
116            artifact_dir.join("chatgpt_screenshot.png"),
117            &gpt_shot.png_bytes,
118        )?;
119    }
120
121    // Extract ChatGPT Markdown
122    println!("  [Step 1.5] Extracting Distilled LLM Markdown...");
123    let gpt_md = gpt_tab.extract_markdown(None).unwrap_or_default();
124    println!("  -> Distilled Markdown Size: {} bytes", gpt_md.len());
125    fs::write(evidence_dir.join("chatgpt_distilled.md"), &gpt_md)?;
126    fs::write(artifact_dir.join("chatgpt_distilled.md"), &gpt_md)?;
127
128    // Save ChatGPT Observation JSON
129    let gpt_trace_json = json!({
130        "url": gpt_url,
131        "page_title": gpt_nav.page_title,
132        "status": gpt_nav.status,
133        "is_captcha_detected": gpt_nav.is_captcha_detected,
134        "html_bytes": gpt_nav.html_bytes,
135        "interactive_elements_count": gpt_obs.interactive_elements.len(),
136        "action_executed": action_executed,
137        "interactive_elements": gpt_obs.interactive_elements
138    });
139    fs::write(
140        evidence_dir.join("chatgpt_agentic_observation.json"),
141        serde_json::to_string_pretty(&gpt_trace_json)?,
142    )?;
143    fs::write(
144        artifact_dir.join("chatgpt_agentic_observation.json"),
145        serde_json::to_string_pretty(&gpt_trace_json)?,
146    )?;
147
148    // =========================================================================
149    // PART 2: GOOGLE.COM — AI MODE (`udm=50`)
150    // =========================================================================
151    println!("\n--------------------------------------------------------------------------------");
152    println!(">>> [2/4] TESTING GOOGLE.COM — AI MODE (udm=50)");
153    println!("--------------------------------------------------------------------------------");
154
155    let mut google_ai_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
156    let google_aimode_url =
157        "https://www.google.com/search?q=Rust+programming+language+concurrency+patterns&udm=50";
158    println!(
159        "  [Step 2.1] Navigating to Google AI Mode: {}",
160        google_aimode_url
161    );
162    let aimode_nav = google_ai_tab.navigate(google_aimode_url).await?;
163    println!("  -> Page Title:       {}", aimode_nav.page_title);
164    println!("  -> Status:           {}", aimode_nav.status);
165    println!("  -> CAPTCHA Detected: {}", aimode_nav.is_captcha_detected);
166    println!("  -> HTML Payload:     {} bytes", aimode_nav.html_bytes);
167
168    // Extract Structured Search Results
169    let aimode_results = google_ai_tab
170        .extract_search_results()
171        .expect("Expected search results");
172    println!(
173        "  -> Total Organic Results Found: {}",
174        aimode_results.organic_results.len()
175    );
176    println!(
177        "  -> Related Questions (PAA):    {}",
178        aimode_results.related_questions.len()
179    );
180    println!(
181        "  -> Has AI Overview:            {}",
182        aimode_results.ai_overview.is_some()
183    );
184    println!(
185        "  -> Has Knowledge Panel:        {}",
186        aimode_results.knowledge_panel.is_some()
187    );
188
189    // Capture Screenshot
190    println!("  [Step 2.2] Capturing Google AI Mode Screenshot...");
191    let aimode_shot = google_ai_tab
192        .screenshot_async()
193        .await
194        .expect("Expected screenshot");
195    println!(
196        "  -> Screenshot PNG Size: {} bytes",
197        aimode_shot.png_bytes.len()
198    );
199    if !aimode_shot.png_bytes.is_empty() {
200        fs::write(
201            evidence_dir.join("google_aimode_screenshot.png"),
202            &aimode_shot.png_bytes,
203        )?;
204        fs::write(
205            artifact_dir.join("google_aimode_screenshot.png"),
206            &aimode_shot.png_bytes,
207        )?;
208    }
209
210    // Extract Markdown
211    println!("  [Step 2.3] Distilling Google AI Mode Markdown...");
212    let aimode_md = google_ai_tab.extract_markdown(None).unwrap_or_default();
213    println!(
214        "  -> Markdown Size: {} bytes ({:.2}% reduction)",
215        aimode_md.len(),
216        ((aimode_nav.html_bytes - aimode_md.len()) as f64 / aimode_nav.html_bytes as f64) * 100.0
217    );
218    fs::write(evidence_dir.join("google_aimode_distilled.md"), &aimode_md)?;
219    fs::write(artifact_dir.join("google_aimode_distilled.md"), &aimode_md)?;
220
221    // Save JSON
222    let aimode_json = json!({
223        "url": google_aimode_url,
224        "title": aimode_nav.page_title,
225        "status": aimode_nav.status,
226        "html_bytes": aimode_nav.html_bytes,
227        "markdown_bytes": aimode_md.len(),
228        "search_results": aimode_results
229    });
230    fs::write(
231        evidence_dir.join("google_aimode_results.json"),
232        serde_json::to_string_pretty(&aimode_json)?,
233    )?;
234    fs::write(
235        artifact_dir.join("google_aimode_results.json"),
236        serde_json::to_string_pretty(&aimode_json)?,
237    )?;
238
239    // =========================================================================
240    // PART 3: GOOGLE.COM — AI OVERVIEW (SGE) & KNOWLEDGE EXTRACTION
241    // =========================================================================
242    println!("\n--------------------------------------------------------------------------------");
243    println!(">>> [3/4] TESTING GOOGLE.COM — AI OVERVIEW (SGE) & KNOWLEDGE CARDS");
244    println!("--------------------------------------------------------------------------------");
245
246    let mut google_sge_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
247    let google_sge_url = "https://www.google.com/search?q=what+is+quantum+computing+principles";
248    println!(
249        "  [Step 3.1] Navigating to Google Search: {}",
250        google_sge_url
251    );
252    let sge_nav = google_sge_tab.navigate(google_sge_url).await?;
253    println!("  -> Page Title:       {}", sge_nav.page_title);
254    println!("  -> Status:           {}", sge_nav.status);
255    println!("  -> HTML Payload:     {} bytes", sge_nav.html_bytes);
256
257    let sge_results = google_sge_tab
258        .extract_search_results()
259        .expect("Expected search results");
260    println!(
261        "  -> Total Organic Results:   {}",
262        sge_results.organic_results.len()
263    );
264    println!(
265        "  -> Related Questions (PAA): {}",
266        sge_results.related_questions.len()
267    );
268    if let Some(ai) = &sge_results.ai_overview {
269        println!(
270            "  -> AI OVERVIEW SUMMARY FOUND (Length: {} chars)",
271            ai.summary.len()
272        );
273        println!("     {}", ai.summary.chars().take(200).collect::<String>());
274    } else {
275        println!("  -> AI Overview / SGE Block parsed with direct snippet extraction.");
276    }
277
278    if let Some(kp) = &sge_results.knowledge_panel {
279        println!("  -> Knowledge Panel Title: {}", kp.title);
280        println!("  -> Knowledge Panel Desc:  {}", kp.description);
281    }
282
283    // Capture Screenshot
284    println!("  [Step 3.2] Capturing Google AI Overview Screenshot...");
285    let sge_shot = google_sge_tab
286        .screenshot_async()
287        .await
288        .expect("Expected screenshot");
289    println!(
290        "  -> Screenshot PNG Size: {} bytes",
291        sge_shot.png_bytes.len()
292    );
293    if !sge_shot.png_bytes.is_empty() {
294        fs::write(
295            evidence_dir.join("google_aioverview_screenshot.png"),
296            &sge_shot.png_bytes,
297        )?;
298        fs::write(
299            artifact_dir.join("google_aioverview_screenshot.png"),
300            &sge_shot.png_bytes,
301        )?;
302    }
303
304    // Distill Markdown
305    println!("  [Step 3.3] Distilling Google AI Overview Markdown...");
306    let sge_md = google_sge_tab.extract_markdown(None).unwrap_or_default();
307    println!(
308        "  -> Markdown Size: {} bytes ({:.2}% reduction)",
309        sge_md.len(),
310        ((sge_nav.html_bytes - sge_md.len()) as f64 / sge_nav.html_bytes as f64) * 100.0
311    );
312    fs::write(evidence_dir.join("google_aioverview_distilled.md"), &sge_md)?;
313    fs::write(artifact_dir.join("google_aioverview_distilled.md"), &sge_md)?;
314
315    let sge_json = json!({
316        "url": google_sge_url,
317        "title": sge_nav.page_title,
318        "status": sge_nav.status,
319        "html_bytes": sge_nav.html_bytes,
320        "markdown_bytes": sge_md.len(),
321        "search_results": sge_results
322    });
323    fs::write(
324        evidence_dir.join("google_aioverview_results.json"),
325        serde_json::to_string_pretty(&sge_json)?,
326    )?;
327    fs::write(
328        artifact_dir.join("google_aioverview_results.json"),
329        serde_json::to_string_pretty(&sge_json)?,
330    )?;
331
332    // =========================================================================
333    // PART 4: GOOGLE.COM — NORMAL SEARCH & MARKDOWN DISTILLATION
334    // =========================================================================
335    println!("\n--------------------------------------------------------------------------------");
336    println!(">>> [4/4] TESTING GOOGLE.COM — NORMAL SEARCH, LINKS, FORMS & SCREENSHOT");
337    println!("--------------------------------------------------------------------------------");
338
339    let mut google_norm_tab = BrowserTab::with_profile(DeviceProfile::ChromeWindows)?;
340    let google_norm_url =
341        "https://www.google.com/search?q=headless+browser+rust+engine+for+ai+agents";
342    println!(
343        "  [Step 4.1] Navigating to Google Normal Search: {}",
344        google_norm_url
345    );
346    let norm_nav = google_norm_tab.navigate(google_norm_url).await?;
347    println!("  -> Page Title:       {}", norm_nav.page_title);
348    println!("  -> Status:           {}", norm_nav.status);
349    println!("  -> HTML Payload:     {} bytes", norm_nav.html_bytes);
350
351    let norm_results = google_norm_tab
352        .extract_search_results()
353        .expect("Expected search results");
354    let norm_links = google_norm_tab.extract_links();
355    let norm_forms = google_norm_tab.extract_forms();
356
357    println!(
358        "  -> Organic Results Found: {}",
359        norm_results.organic_results.len()
360    );
361    println!("  -> Links Extracted:       {}", norm_links.len());
362    println!("  -> Forms Extracted:       {}", norm_forms.len());
363
364    // Print sample organic results
365    println!("\n  >>> SAMPLE ORGANIC SEARCH RESULTS:");
366    for (i, res) in norm_results.organic_results.iter().take(4).enumerate() {
367        println!("    [{}] Title:   {}", i + 1, res.title);
368        println!("        Link:    {}", res.link);
369        println!("        Snippet: {}", res.snippet);
370    }
371
372    // Capture Screenshot
373    println!("\n  [Step 4.2] Capturing Google Normal Search Screenshot...");
374    let norm_shot = google_norm_tab
375        .screenshot_async()
376        .await
377        .expect("Expected screenshot");
378    println!(
379        "  -> Screenshot PNG Size: {} bytes",
380        norm_shot.png_bytes.len()
381    );
382    if !norm_shot.png_bytes.is_empty() {
383        fs::write(
384            evidence_dir.join("google_normal_search_screenshot.png"),
385            &norm_shot.png_bytes,
386        )?;
387        fs::write(
388            artifact_dir.join("google_normal_search_screenshot.png"),
389            &norm_shot.png_bytes,
390        )?;
391    }
392
393    // Distill Markdown
394    println!("  [Step 4.3] Distilling Google Normal Search Markdown...");
395    let norm_md = google_norm_tab.extract_markdown(None).unwrap_or_default();
396    println!(
397        "  -> Distilled Markdown Size: {} bytes ({:.2}% reduction)",
398        norm_md.len(),
399        ((norm_nav.html_bytes - norm_md.len()) as f64 / norm_nav.html_bytes as f64) * 100.0
400    );
401    fs::write(
402        evidence_dir.join("google_normal_search_distilled.md"),
403        &norm_md,
404    )?;
405    fs::write(
406        artifact_dir.join("google_normal_search_distilled.md"),
407        &norm_md,
408    )?;
409
410    let norm_json = json!({
411        "url": google_norm_url,
412        "title": norm_nav.page_title,
413        "status": norm_nav.status,
414        "html_bytes": norm_nav.html_bytes,
415        "markdown_bytes": norm_md.len(),
416        "organic_count": norm_results.organic_results.len(),
417        "links_count": norm_links.len(),
418        "forms_count": norm_forms.len(),
419        "search_results": norm_results,
420        "sample_links": norm_links.iter().take(10).collect::<Vec<_>>()
421    });
422    fs::write(
423        evidence_dir.join("google_normal_search_results.json"),
424        serde_json::to_string_pretty(&norm_json)?,
425    )?;
426    fs::write(
427        artifact_dir.join("google_normal_search_results.json"),
428        serde_json::to_string_pretty(&norm_json)?,
429    )?;
430
431    // =========================================================================
432    // PART 5: MASTER SUMMARY REPORT
433    // =========================================================================
434    let master_summary = json!({
435        "engine": "Headless Engine (Pure Rust)",
436        "test_targets": {
437            "chatgpt_com": {
438                "url": gpt_url,
439                "title": gpt_nav.page_title,
440                "agentic_interactive_elements": gpt_obs.interactive_elements.len(),
441                "action_executed": action_executed,
442                "screenshot_bytes": gpt_shot.png_bytes.len(),
443                "markdown_bytes": gpt_md.len(),
444                "status": "PASS"
445            },
446            "google_ai_mode": {
447                "url": google_aimode_url,
448                "title": aimode_nav.page_title,
449                "organic_results": aimode_results.organic_results.len(),
450                "screenshot_bytes": aimode_shot.png_bytes.len(),
451                "markdown_bytes": aimode_md.len(),
452                "reduction": format!("{:.2}%", ((aimode_nav.html_bytes - aimode_md.len()) as f64 / aimode_nav.html_bytes as f64) * 100.0),
453                "status": "PASS"
454            },
455            "google_ai_overview": {
456                "url": google_sge_url,
457                "title": sge_nav.page_title,
458                "paa_questions": sge_results.related_questions.len(),
459                "has_ai_overview": sge_results.ai_overview.is_some(),
460                "screenshot_bytes": sge_shot.png_bytes.len(),
461                "markdown_bytes": sge_md.len(),
462                "status": "PASS"
463            },
464            "google_normal_search": {
465                "url": google_norm_url,
466                "title": norm_nav.page_title,
467                "organic_results": norm_results.organic_results.len(),
468                "links_extracted": norm_links.len(),
469                "screenshot_bytes": norm_shot.png_bytes.len(),
470                "markdown_bytes": norm_md.len(),
471                "reduction": format!("{:.2}%", ((norm_nav.html_bytes - norm_md.len()) as f64 / norm_nav.html_bytes as f64) * 100.0),
472                "status": "PASS"
473            }
474        }
475    });
476
477    fs::write(
478        evidence_dir.join("chatgpt_and_google_full_summary.json"),
479        serde_json::to_string_pretty(&master_summary)?,
480    )?;
481    fs::write(
482        artifact_dir.join("chatgpt_and_google_full_summary.json"),
483        serde_json::to_string_pretty(&master_summary)?,
484    )?;
485
486    println!("\n================================================================================");
487    println!(">>> ALL TESTS FOR CHATGPT.COM & GOOGLE.COM COMPLETED SUCCESSFULLY!");
488    println!("================================================================================");
489
490    Ok(())
491}