fix(eval): replMode only for sync let/const decls, keep awaitPromise for async (#38)
replMode and awaitPromise are mutually exclusive in Chrome — under replMode a
returned promise serialises to {} instead of being awaited, which broke every
fetch/async eval (e2e_domain_filter, e2e_headers, e2e_react_tree all regressed).
Enable replMode only for synchronous scripts that declare a top-level let/const
(the #38 case); promise-returning scripts keep awaitPromise — restoring the
pre-#38 await behaviour while still fixing the let-redeclaration collision.
This commit is contained in:
@@ -1208,13 +1208,21 @@ impl BrowserManager {
|
|||||||
pub async fn evaluate(&self, script: &str, _args: Option<Value>) -> Result<Value, String> {
|
pub async fn evaluate(&self, script: &str, _args: Option<Value>) -> Result<Value, String> {
|
||||||
let session_id = self.active_session_id()?.to_string();
|
let session_id = self.active_session_id()?.to_string();
|
||||||
|
|
||||||
// `replMode: true` matches the DevTools console: top-level `let`/`const`
|
// `replMode: true` lets successive `eval`s re-declare top-level
|
||||||
// can be re-declared across successive `eval`s instead of throwing
|
// `let`/`const` instead of throwing "Identifier 'x' has already been
|
||||||
// "Identifier 'x' has already been declared" (issue #38 — independent
|
// declared" (issue #38 — independent `eval` steps in a test suite collided
|
||||||
// `eval` steps in a test suite collided in the page's shared lexical
|
// in the page's shared lexical scope). BUT replMode and `awaitPromise` are
|
||||||
// scope), and top-level `await` is allowed. Completion-value and
|
// mutually exclusive in Chrome: under replMode a returned promise is NOT
|
||||||
// main-world semantics are unchanged. Built as raw params so the other
|
// awaited (it serialises to `{}`), which breaks `fetch(...).then(...)` and
|
||||||
// ~28 EvaluateParams literals don't all need a new field.
|
// every other async eval. So enable replMode ONLY for synchronous scripts
|
||||||
|
// that declare a top-level `let`/`const`; promise-returning scripts keep
|
||||||
|
// `awaitPromise` (no replMode) — exactly the pre-#38 behaviour.
|
||||||
|
let mentions_async = script.contains("await")
|
||||||
|
|| script.contains(".then(")
|
||||||
|
|| script.contains("fetch(")
|
||||||
|
|| script.contains("Promise");
|
||||||
|
let declares = script.contains("let ") || script.contains("const ");
|
||||||
|
let repl_mode = declares && !mentions_async;
|
||||||
let result: EvaluateResult = self
|
let result: EvaluateResult = self
|
||||||
.client
|
.client
|
||||||
.send_command_typed(
|
.send_command_typed(
|
||||||
@@ -1222,8 +1230,8 @@ impl BrowserManager {
|
|||||||
&json!({
|
&json!({
|
||||||
"expression": script,
|
"expression": script,
|
||||||
"returnByValue": true,
|
"returnByValue": true,
|
||||||
"awaitPromise": true,
|
"awaitPromise": !repl_mode,
|
||||||
"replMode": true,
|
"replMode": repl_mode,
|
||||||
}),
|
}),
|
||||||
Some(&session_id),
|
Some(&session_id),
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user