201 lines
6.7 KiB
Rust
201 lines
6.7 KiB
Rust
use serde_json::{json, Value};
|
|
use sgclaw::browser::ws_protocol::{decode_callback_frame, encode_v1_action};
|
|
use sgclaw::pipe::Action;
|
|
|
|
#[test]
|
|
fn encodes_navigate_frame_exactly_as_browser_array() {
|
|
let request = encode_v1_action(
|
|
&Action::Navigate,
|
|
&json!({ "url": "https://www.baidu.com" }),
|
|
"https://www.zhihu.com/hot",
|
|
Some("req42"),
|
|
)
|
|
.unwrap();
|
|
|
|
assert_eq!(
|
|
request.payload,
|
|
r#"["https://www.zhihu.com/hot","sgHideBrowserCallAfterLoaded","https://www.baidu.com","callBackJsToCpp(\"https://www.zhihu.com/hot@_@https://www.baidu.com@_@sgclaw_cb_req42@_@sgHideBrowserCallAfterLoaded@_@\")"]"#
|
|
);
|
|
let callback = request.callback.unwrap();
|
|
assert_eq!(callback.request_id, "req42");
|
|
assert_eq!(callback.callback_name, "sgclaw_cb_req42");
|
|
assert_eq!(callback.source_url, "https://www.zhihu.com/hot");
|
|
assert_eq!(callback.target_url, "https://www.baidu.com");
|
|
assert_eq!(callback.action_url, "sgHideBrowserCallAfterLoaded");
|
|
}
|
|
|
|
#[test]
|
|
fn encodes_get_text_frame_with_documented_callback_action_url() {
|
|
let request = encode_v1_action(
|
|
&Action::GetText,
|
|
&json!({
|
|
"target_url": "https://www.zhihu.com/hot",
|
|
"selector": "#content"
|
|
}),
|
|
"https://www.zhihu.com/hot",
|
|
Some("req42"),
|
|
)
|
|
.unwrap();
|
|
|
|
let payload: Value = serde_json::from_str(&request.payload).unwrap();
|
|
assert_eq!(
|
|
payload,
|
|
json!([
|
|
"https://www.zhihu.com/hot",
|
|
"sgBrowserExcuteJsCodeByArea",
|
|
"https://www.zhihu.com/hot",
|
|
"(function(){const el=document.querySelector(\"#content\");if(!el){throw new Error(\"selector not found: #content\");}const text=el.innerText ?? el.textContent ?? \"\";callBackJsToCpp(\"https://www.zhihu.com/hot@_@https://www.zhihu.com/hot@_@sgclaw_cb_req42@_@sgBrowserExcuteJsCodeByArea@_@\"+String(text));})();",
|
|
"hide"
|
|
])
|
|
);
|
|
let callback = request.callback.unwrap();
|
|
assert_eq!(callback.request_id, "req42");
|
|
assert_eq!(callback.callback_name, "sgclaw_cb_req42");
|
|
assert_eq!(callback.source_url, "https://www.zhihu.com/hot");
|
|
assert_eq!(callback.target_url, "https://www.zhihu.com/hot");
|
|
assert_eq!(callback.action_url, "sgBrowserExcuteJsCodeByArea");
|
|
}
|
|
|
|
#[test]
|
|
fn decodes_callback_payload_from_browser_frame() {
|
|
let callback = decode_callback_frame(
|
|
r#"["https://www.zhihu.com/hot","callBackJsToCpp","https://www.zhihu.com/hot@_@https://www.zhihu.com/hot@_@sgclaw_cb_req42@_@sgBrowserExcuteJsCodeByArea@_@天气"]"#,
|
|
)
|
|
.unwrap();
|
|
|
|
assert_eq!(callback.source_url, "https://www.zhihu.com/hot");
|
|
assert_eq!(callback.target_url, "https://www.zhihu.com/hot");
|
|
assert_eq!(callback.callback_name, "sgclaw_cb_req42");
|
|
assert_eq!(callback.action_url, "sgBrowserExcuteJsCodeByArea");
|
|
assert_eq!(callback.response_text, "天气");
|
|
}
|
|
|
|
#[test]
|
|
fn rejects_malformed_callback_frames_and_missing_request_ids() {
|
|
let malformed = decode_callback_frame(
|
|
r#"["https://www.zhihu.com/hot","callBackJsToCpp","https://www.zhihu.com/hot@_@too-short"]"#,
|
|
)
|
|
.unwrap_err();
|
|
assert!(malformed.to_string().contains("malformed callback payload"));
|
|
|
|
let wrong_function =
|
|
decode_callback_frame(r#"["https://www.zhihu.com/hot","sgBrowerserOpenPage","0"]"#)
|
|
.unwrap_err();
|
|
assert!(wrong_function
|
|
.to_string()
|
|
.contains("callback frame must target callBackJsToCpp"));
|
|
|
|
let missing_request_id = encode_v1_action(
|
|
&Action::Eval,
|
|
&json!({
|
|
"target_url": "https://www.zhihu.com/hot",
|
|
"script": "2 + 2"
|
|
}),
|
|
"https://www.zhihu.com/hot",
|
|
None,
|
|
)
|
|
.unwrap_err();
|
|
assert!(missing_request_id
|
|
.to_string()
|
|
.contains("request_id is required"));
|
|
}
|
|
|
|
#[test]
|
|
fn eval_uses_documented_js_opcode_for_callback_action_url() {
|
|
let request = encode_v1_action(
|
|
&Action::Eval,
|
|
&json!({
|
|
"target_url": "https://www.zhihu.com/hot",
|
|
"script": "2 + 2"
|
|
}),
|
|
"https://www.zhihu.com/hot",
|
|
Some("req-eval"),
|
|
)
|
|
.unwrap();
|
|
|
|
let callback = request.callback.unwrap();
|
|
assert_eq!(callback.callback_name, "sgclaw_cb_req-eval");
|
|
assert_eq!(callback.action_url, "sgBrowserExcuteJsCodeByArea");
|
|
|
|
let payload: Value = serde_json::from_str(&request.payload).unwrap();
|
|
let js = payload[3].as_str().unwrap();
|
|
assert!(js.contains("callBackJsToCpp(\"https://www.zhihu.com/hot@_@https://www.zhihu.com/hot@_@sgclaw_cb_req-eval@_@sgBrowserExcuteJsCodeByArea@_@\"+String(result))"));
|
|
}
|
|
|
|
#[test]
|
|
fn covers_supported_v1_action_mapping_and_rejects_unsupported_actions() {
|
|
let cases = vec![
|
|
(
|
|
Action::Navigate,
|
|
json!({ "url": "https://www.baidu.com" }),
|
|
Some("req-nav"),
|
|
"sgHideBrowserCallAfterLoaded",
|
|
true,
|
|
),
|
|
(
|
|
Action::Click,
|
|
json!({
|
|
"target_url": "https://www.zhihu.com/hot",
|
|
"selector": "#submit"
|
|
}),
|
|
None,
|
|
"sgBrowserExcuteJsCodeByArea",
|
|
false,
|
|
),
|
|
(
|
|
Action::Type,
|
|
json!({
|
|
"target_url": "https://www.zhihu.com/hot",
|
|
"selector": "#kw",
|
|
"text": "天气"
|
|
}),
|
|
None,
|
|
"sgBrowserExcuteJsCodeByArea",
|
|
false,
|
|
),
|
|
(
|
|
Action::GetText,
|
|
json!({
|
|
"target_url": "https://www.zhihu.com/hot",
|
|
"selector": "#content"
|
|
}),
|
|
Some("req-get-text"),
|
|
"sgBrowserExcuteJsCodeByArea",
|
|
true,
|
|
),
|
|
(
|
|
Action::Eval,
|
|
json!({
|
|
"target_url": "https://www.zhihu.com/hot",
|
|
"script": "2 + 2"
|
|
}),
|
|
Some("req-eval"),
|
|
"sgBrowserExcuteJsCodeByArea",
|
|
true,
|
|
),
|
|
];
|
|
|
|
for (action, params, request_id, browser_function, expects_callback) in cases {
|
|
let request =
|
|
encode_v1_action(&action, ¶ms, "https://www.zhihu.com/hot", request_id).unwrap();
|
|
let payload: Value = serde_json::from_str(&request.payload).unwrap();
|
|
assert_eq!(payload[1], json!(browser_function), "action={action:?}");
|
|
assert_eq!(
|
|
request.callback.is_some(),
|
|
expects_callback,
|
|
"action={action:?}"
|
|
);
|
|
}
|
|
|
|
let unsupported = encode_v1_action(
|
|
&Action::GetHtml,
|
|
&json!({ "selector": "body" }),
|
|
"https://www.zhihu.com/hot",
|
|
None,
|
|
)
|
|
.unwrap_err();
|
|
assert!(unsupported
|
|
.to_string()
|
|
.contains("unsupported browser ws action"));
|
|
}
|