test(lifecycle): gate post-DCL script load deterministically

This commit is contained in:
ldm0
2026-09-09 06:31:04 +08:00
parent 9a81e13ace
commit e23e5deffa
5 changed files with 67 additions and 2 deletions
+4 -1
View File
@@ -579,11 +579,14 @@ async fn fetch_with_domcontentloaded_stops_before_runtime_owned_script_load_even
let page = browser
.fetch_with_wait_until(
&server.url("/compat/runtime-owned-external-in-order-load-after-domcontentloaded"),
&server.url(
"/compat/runtime-owned-external-in-order-load-after-domcontentloaded?manual-release",
),
RenderedDomWaitUntil::DomContentLoaded,
Duration::from_secs(5),
)
.await?;
server.release_runtime_owned_in_order_load_after_dcl();
assert_eq!(
diagnostic_global(&page, "runtimeOwnedInOrderLoadAfterDcl"),
@@ -6,7 +6,7 @@
window.runtimeOwnedInOrderLoadOrder = [];
const script = document.createElement("script");
script.async = false;
script.src = "/assets/runtime_owned_in_order_load_slow.js";
script.src = "/assets/runtime_owned_in_order_load_after_dcl_gated.js";
script.onload = () => {
window.runtimeOwnedInOrderLoadOrder.push("load");
queueMicrotask(() => {
@@ -21,6 +21,11 @@
window.runtimeOwnedInOrderLoadOrder.push("dcl");
window.runtimeOwnedInOrderLoadAfterDcl =
window.runtimeOwnedInOrderLoadOrder.join(",");
if (!location.search.includes("manual-release")) {
void fetch(
"/compat/runtime-owned-external-in-order-load-after-domcontentloaded-release",
);
}
});
window.addEventListener("load", () => {
window.runtimeOwnedInOrderLoadOrder.push("window-load");
+43
View File
@@ -18,6 +18,9 @@ static RUNTIME_OWNED_ASYNC_CHUNKED_TAIL_GATES: OnceLock<
static RUNTIME_OWNED_IN_ORDER_ERROR_AFTER_DCL_GATES: OnceLock<
Mutex<HashMap<String, Arc<tokio::sync::Notify>>>,
> = OnceLock::new();
static RUNTIME_OWNED_IN_ORDER_LOAD_AFTER_DCL_GATES: OnceLock<
Mutex<HashMap<String, Arc<tokio::sync::Notify>>>,
> = OnceLock::new();
struct ConcurrentSharedStateRequestGuard;
@@ -145,6 +148,27 @@ pub(crate) fn notify_runtime_owned_in_order_error_after_dcl_gate(host_key: &str)
runtime_owned_in_order_error_after_dcl_gate(host_key).notify_one();
}
fn runtime_owned_in_order_load_after_dcl_gate(host_key: &str) -> Arc<tokio::sync::Notify> {
let gates =
RUNTIME_OWNED_IN_ORDER_LOAD_AFTER_DCL_GATES.get_or_init(|| Mutex::new(HashMap::new()));
let mut gates = gates.lock();
gates
.entry(host_key.to_owned())
.or_insert_with(|| Arc::new(tokio::sync::Notify::new()))
.clone()
}
fn remove_runtime_owned_in_order_load_after_dcl_gate(host_key: &str) {
let Some(gates) = RUNTIME_OWNED_IN_ORDER_LOAD_AFTER_DCL_GATES.get() else {
return;
};
gates.lock().remove(host_key);
}
pub(crate) fn notify_runtime_owned_in_order_load_after_dcl_gate(host_key: &str) {
runtime_owned_in_order_load_after_dcl_gate(host_key).notify_one();
}
pub(super) async fn static_page() -> Html<&'static str> {
Html(STATIC_HTML)
}
@@ -2503,6 +2527,14 @@ pub(super) async fn runtime_owned_external_in_order_load_after_domcontentloaded_
Html(RUNTIME_OWNED_EXTERNAL_IN_ORDER_LOAD_AFTER_DOMCONTENTLOADED_HTML)
}
pub(super) async fn release_runtime_owned_external_in_order_load_after_domcontentloaded(
headers: HeaderMap,
) -> StatusCode {
let host_key = request_host_key(&headers).unwrap_or_default();
notify_runtime_owned_in_order_load_after_dcl_gate(&host_key);
StatusCode::NO_CONTENT
}
pub(super) async fn runtime_owned_external_in_order_with_defer_stays_after_domcontentloaded_page()
-> Html<&'static str> {
Html(RUNTIME_OWNED_EXTERNAL_IN_ORDER_WITH_DEFER_STAYS_AFTER_DOMCONTENTLOADED_HTML)
@@ -4307,6 +4339,17 @@ pub(super) async fn asset_runtime_owned_in_order_load_script() -> Response {
javascript_response(RUNTIME_OWNED_IN_ORDER_LOAD_JS)
}
pub(super) async fn asset_runtime_owned_in_order_load_after_dcl_gated_script(
headers: HeaderMap,
) -> Response {
let host_key = request_host_key(&headers).unwrap_or_default();
runtime_owned_in_order_load_after_dcl_gate(&host_key)
.notified()
.await;
remove_runtime_owned_in_order_load_after_dcl_gate(&host_key);
javascript_response(RUNTIME_OWNED_IN_ORDER_LOAD_JS)
}
pub(super) async fn asset_missing_runtime_owned_in_order_error_script(
headers: HeaderMap,
) -> Response {
+6
View File
@@ -45,6 +45,12 @@ impl FixtureServer {
);
}
pub fn release_runtime_owned_in_order_load_after_dcl(&self) {
crate::routes_core::notify_runtime_owned_in_order_load_after_dcl_gate(
&self.addr.to_string(),
);
}
pub async fn shutdown(mut self) {
if let Some(shutdown_tx) = self.shutdown_tx.take() {
let _ = shutdown_tx.send(());
+8
View File
@@ -1412,6 +1412,10 @@ pub(super) fn build_router() -> Router {
"/compat/runtime-owned-external-in-order-load-after-domcontentloaded",
get(runtime_owned_external_in_order_load_after_domcontentloaded_page),
)
.route(
"/compat/runtime-owned-external-in-order-load-after-domcontentloaded-release",
get(release_runtime_owned_external_in_order_load_after_domcontentloaded),
)
.route(
"/compat/runtime-owned-external-in-order-with-defer-stays-after-domcontentloaded",
get(runtime_owned_external_in_order_with_defer_stays_after_domcontentloaded_page),
@@ -2133,6 +2137,10 @@ pub(super) fn build_router() -> Router {
"/assets/runtime_owned_in_order_load.js",
get(asset_runtime_owned_in_order_load_script),
)
.route(
"/assets/runtime_owned_in_order_load_after_dcl_gated.js",
get(asset_runtime_owned_in_order_load_after_dcl_gated_script),
)
.route(
"/assets/missing_runtime_owned_in_order_error.js",
get(asset_missing_runtime_owned_in_order_error_script),