This PR runs `prettier`'s formatting for all markdown documents under best practices. This ia completely mechanical change. Additionally, we also update the claude `add-best-practice` skill to be aware of the auto-formatter. Bug: N/A
3.4 KiB
3.4 KiB
JavaScript Evaluation in Tests
✅ Prefer Event-Driven JavaScript Over C++ Polling
When waiting for DOM changes, prefer JavaScript event-driven patterns (like MutationObserver) over C++ polling loops.
Event-driven patterns are:
- More deterministic (respond immediately when the event occurs)
- More efficient (no wasted CPU cycles polling)
- Consistent with Chromium patterns (see
service_worker_internals_ui_browsertest.cc)
BEST - MutationObserver for DOM changes:
// Pattern from Chromium's service_worker_internals_ui_browsertest.cc
static constexpr char kWaitForTextScript[] = R"(
(function() {
const element = document.getElementById($1);
const expected = $2;
function getText() {
return element.tagName === 'INPUT' || element.tagName === 'TEXTAREA'
? element.value : element.innerText;
}
if (getText() === expected) {
return getText();
}
return new Promise(function(resolve) {
const observer = new MutationObserver(function() {
if (getText() === expected) {
observer.disconnect();
resolve(getText());
}
});
observer.observe(element,
{childList: true, subtree: true, characterData: true});
});
})()
)";
std::string updated_text =
content::EvalJs(web_contents,
content::JsReplace(kWaitForTextScript,
element_id,
expected_text))
.ExtractString();
✅ Manual Polling Loop (Fallback)
Use C++ polling only when JavaScript event-driven patterns aren't applicable (e.g., checking for element existence, waiting for JS API readiness):
const base::TimeTicks deadline = base::TimeTicks::Now() + base::Seconds(10);
for (;;) {
NonBlockingDelay(base::Milliseconds(10));
if (content::EvalJs(web_contents, "!!document.getElementById('foo')",
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL)
.ExtractBool()) {
break;
}
if (base::TimeTicks::Now() >= deadline) {
FAIL() << "Timeout waiting for element";
}
}
Use Isolated Worlds for Test Code
When evaluating JavaScript in tests, use ISOLATED_WORLD_ID_BRAVE_INTERNAL to
avoid interfering with page scripts:
content::EvalJs(web_contents, "document.getElementById('foo')",
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL)
Wait for Renderer-Side JS Setup
Problem: Mojo binding completes before JavaScript event emitter setup.
Example (Solana provider):
// ❌ WRONG - WaitForSolanaProviderBinding only waits for mojo, not JS
WaitForSolanaProviderBinding();
// window.braveSolana.on might not be ready yet!
// ✅ CORRECT - Manual polling for JS API readiness
const base::TimeTicks deadline = base::TimeTicks::Now() + base::Seconds(5);
for (;;) {
NonBlockingDelay(base::Milliseconds(10));
if (content::EvalJs(web_contents,
"typeof window.braveSolana?.on === 'function'",
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL)
.ExtractBool()) {
break;
}
if (base::TimeTicks::Now() >= deadline) {
FAIL() << "Timeout waiting for braveSolana.on";
}
}