use super::*;
#[test]
fn extract_probes_finds_navigator_webdriver() {
let js = "if(navigator.webdriver){return false;}";
let probes = extract_probes(js);
assert!(probes.contains(&ProbeSurface::new("navigator", "webdriver")));
}
#[test]
fn extract_probes_finds_multi_namespace_probes() {
let js = r#"
const a = navigator.userAgent;
const b = window.chrome;
const c = document.referrer;
const d = screen.width;
const e = WebGLRenderingContext.UNMASKED_VENDOR_WEBGL;
"#;
let probes = extract_probes(js);
assert!(probes.contains(&ProbeSurface::new("navigator", "userAgent")));
assert!(probes.contains(&ProbeSurface::new("window", "chrome")));
assert!(probes.contains(&ProbeSurface::new("document", "referrer")));
assert!(probes.contains(&ProbeSurface::new("screen", "width")));
assert!(probes.contains(&ProbeSurface::new(
"WebGLRenderingContext",
"UNMASKED_VENDOR_WEBGL"
)));
}
#[test]
fn extract_probes_deduplicates_repeats() {
let js = r#"
navigator.webdriver;
navigator.webdriver;
navigator.webdriver;
"#;
let probes = extract_probes(js);
assert_eq!(
probes.iter().filter(|p| p.property == "webdriver").count(),
1
);
}
#[test]
fn extract_probes_filters_js_reserved_words() {
let js = "navigator.then(()=>{});navigator.toString();navigator.length;";
let probes = extract_probes(js);
assert!(!probes
.iter()
.any(|p| matches!(p.property.as_str(), "then" | "toString" | "length")));
}
#[test]
fn extract_probes_respects_left_word_boundary() {
let js = "xnavigator.foo;navigator.bar;";
let probes = extract_probes(js);
assert!(probes.contains(&ProbeSurface::new("navigator", "bar")));
assert!(!probes.contains(&ProbeSurface::new("navigator", "foo")));
}
#[test]
fn extract_probes_handles_empty_input() {
assert!(extract_probes("").is_empty());
assert!(extract_probes("// just a comment").is_empty());
}
#[test]
fn extract_probes_skips_minified_short_identifiers_correctly() {
let js = "var e=navigator;var t=window;t.chrome;navigator.platform;";
let probes = extract_probes(js);
assert!(probes.contains(&ProbeSurface::new("navigator", "platform")));
assert!(
!probes.contains(&ProbeSurface::new("window", "chrome")),
"aliased access via `t.chrome` should NOT resolve to window.chrome"
);
}
#[test]
fn scrape_diff_returns_new_probes_when_baseline_is_empty() {
let mut s = VendorJsScraper::new();
s.set_baseline("test_vendor", HashSet::new());
let probes_now: HashSet<ProbeSurface> =
extract_probes("navigator.webdriver;navigator.platform;")
.into_iter()
.collect();
let baseline = s.baseline("test_vendor").unwrap().clone();
let new: HashSet<_> = probes_now.difference(&baseline).cloned().collect();
assert_eq!(new.len(), 2);
}
#[test]
fn scrape_diff_detects_added_probes_between_runs() {
let mut s = VendorJsScraper::new();
let v1: HashSet<ProbeSurface> = extract_probes("navigator.webdriver;").into_iter().collect();
s.set_baseline("v", v1.clone());
let v2: HashSet<ProbeSurface> = extract_probes("navigator.webdriver;navigator.platform;")
.into_iter()
.collect();
let added: Vec<_> = v2.difference(&v1).cloned().collect();
assert_eq!(added.len(), 1);
assert_eq!(added[0].property, "platform");
}
#[test]
fn scrape_diff_detects_removed_probes_between_runs() {
let v1: HashSet<ProbeSurface> =
extract_probes("navigator.webdriver;navigator.userAgent;navigator.platform;")
.into_iter()
.collect();
let v2: HashSet<ProbeSurface> = extract_probes("navigator.webdriver;navigator.platform;")
.into_iter()
.collect();
let removed: Vec<_> = v1.difference(&v2).cloned().collect();
assert_eq!(removed.len(), 1);
assert_eq!(removed[0].property, "userAgent");
}
#[test]
fn scrape_report_summary_lists_new_probes() {
let r = ScrapeReport {
vendor: "demo".into(),
urls_fetched: vec!["https://example.com/api.js".into()],
bytes_total: 1234,
probes_total: 1,
probes_new: vec![ProbeSurface::new("navigator", "newProbe")],
probes_removed: vec![],
probes_stable: vec![],
};
let s = r.render_summary();
assert!(s.contains("vendor: demo"));
assert!(s.contains("new probes: 1"));
assert!(s.contains("navigator.newProbe"));
}
#[test]
fn scrape_report_summary_lists_removed_probes() {
let r = ScrapeReport {
vendor: "demo".into(),
urls_fetched: vec![],
bytes_total: 0,
probes_total: 0,
probes_new: vec![],
probes_removed: vec![ProbeSurface::new("window", "deprecated")],
probes_stable: vec![],
};
let s = r.render_summary();
assert!(s.contains("window.deprecated"));
assert!(s.contains("removed:"));
}
#[test]
fn bundled_targets_cover_the_four_most_deployed_vendors() {
let targets = bundled_targets();
let names: Vec<&str> = targets.iter().map(|t| t.name.as_str()).collect();
assert!(names.contains(&"cloudflare-turnstile"));
assert!(names.contains(&"hcaptcha"));
assert!(names.contains(&"recaptcha-v2"));
assert!(names.contains(&"datadome"));
}
#[test]
fn every_bundled_target_has_at_least_one_url() {
for t in bundled_targets() {
assert!(!t.urls.is_empty(), "{} has no URLs", t.name);
}
}
#[test]
fn probe_surface_displays_as_dotted_path() {
let p = ProbeSurface::new("navigator", "webdriver");
assert_eq!(p.to_string(), "navigator.webdriver");
}