use std::path::Path;
use std::time::Duration;
use drission::prelude::*;
use tokio::time::sleep;
const PAGE: &str = r##"<!doctype html><html><head><meta charset="utf-8"><style>
body{font:14px monospace;padding:16px}
#wrap{position:relative;width:300px;height:150px;outline:1px solid #ccc}
#bg{position:absolute;left:0;top:0;width:300px;height:150px}
#piece{position:absolute;top:55px;left:10px;width:40px;height:40px}
#track{position:relative;margin-top:12px;width:300px;height:30px;background:#eee;border-radius:15px}
#handle{position:absolute;left:0;top:0;width:30px;height:30px;background:#4a90e2;border-radius:15px;cursor:pointer}
#status{margin-top:10px}
.ok{color:green;font-weight:bold}
</style></head><body>
<div id="wrap"><img id="bg"><img id="piece"></div>
<div id="track"><div id="handle"></div></div>
<div id="status">idle</div>
<script>
var W=300,H=150,PS=40,PIECE_START=10,RATIO=0.9;
var gapX=110+Math.floor(Math.random()*70), gapY=55; // 缺口左缘 110..179
(function(){ // 背景图 + 缺口
var c=document.createElement('canvas');c.width=W;c.height=H;var x=c.getContext('2d');
var g=x.createLinearGradient(0,0,W,H);g.addColorStop(0,'#99aadd');g.addColorStop(1,'#55aa88');
x.fillStyle=g;x.fillRect(0,0,W,H);
for(var i=0;i<400;i++){x.fillStyle='rgba(255,255,255,'+(Math.random()*0.12)+')';x.fillRect(Math.random()*W|0,Math.random()*H|0,2,2);}
x.fillStyle='rgba(0,0,0,0.45)';x.fillRect(gapX,gapY,PS,PS);
x.strokeStyle='rgba(255,255,255,0.95)';x.lineWidth=2;x.strokeRect(gapX+1,gapY+1,PS-2,PS-2);
document.getElementById('bg').src=c.toDataURL();
})();
(function(){ // 拼图块(同形方块)
var c=document.createElement('canvas');c.width=PS;c.height=PS;var x=c.getContext('2d');
x.fillStyle='#777777';x.fillRect(0,0,PS,PS);
x.strokeStyle='rgba(255,255,255,0.95)';x.lineWidth=2;x.strokeRect(1,1,PS-2,PS-2);
document.getElementById('piece').src=c.toDataURL();
})();
var handle=document.getElementById('handle'),piece=document.getElementById('piece'),status=document.getElementById('status');
var dragging=false,sx=0,ht=0; window.__ok=false;
document.addEventListener('mousedown',function(e){dragging=true;sx=e.clientX;status.textContent='drag';},true);
document.addEventListener('mousemove',function(e){ if(!dragging)return; var dx=e.clientX-sx;
ht=Math.max(0,Math.min(W-30,dx)); handle.style.transform='translateX('+ht+'px)'; piece.style.transform='translateX('+(ht*RATIO)+'px)'; },true);
document.addEventListener('mouseup',function(e){ if(!dragging)return; dragging=false;
var pl=PIECE_START+ht*RATIO;
if(Math.abs(pl-gapX)<=6){window.__ok=true;status.textContent='OK';status.className='ok';}
else{status.textContent='retry '+Math.round(pl-gapX);} },true);
</script>
</body></html>"##;
#[tokio::main]
async fn main() -> drission::Result<()> {
let headless = std::env::var("HL").map(|v| v != "0").unwrap_or(true);
let dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("target/slider-fixture");
std::fs::create_dir_all(&dir).ok();
let page = dir.join("page.html");
std::fs::write(&page, PAGE).map_err(|e| drission::Error::msg(format!("写页面失败: {e}")))?;
let url = format!("file://{}", page.display());
let browser = Browser::launch(BrowserOptions::new().headless(headless)).await?;
let tab = browser.latest_tab().await?;
println!("[*] 打开本地合成滑块页 {url}");
tab.get(&url).await?;
tab.wait().ele_displayed("#handle", None).await?;
sleep(Duration::from_millis(600)).await;
let cfg = SliderConfig::new(ImageSource::img("#bg"), "#handle")
.piece(ImageSource::img("#piece"))
.success(SuccessCheck::Js("window.__ok===true".into()))
.max_attempts(4);
match tab.slider_gap(&cfg).await {
Ok(g) => println!(
"[*] slider_gap():拼图需移 {:.0}px(法={:?} 置信 {:.2})",
g.displace, g.method, g.confidence
),
Err(e) => println!("[!] slider_gap 失败: {e}"),
}
let r = tab.solve_slider(&cfg).await?;
println!(
"[*] solve_slider:passed={} 尝试={} 对齐误差={:.1}px",
r.passed, r.attempts, r.align_error
);
let mut ok = true;
if !r.passed {
println!("[FAIL] 未通过本地合成滑块");
ok = false;
}
if r.align_error.is_finite() && r.align_error.abs() > 6.0 {
println!("[FAIL] 对齐误差过大: {:.1}px", r.align_error);
ok = false;
}
if !headless {
sleep(Duration::from_secs(2)).await;
}
browser.quit().await?;
if ok {
println!("\nALL CHECKS PASSED");
Ok(())
} else {
Err(drission::Error::msg("本地合成滑块自验证失败"))
}
}