fix: improve async tests stability and performance

This commit is contained in:
Ryan Turnquist 2025-12-05 11:02:40 -08:00
parent 40413b7da9
commit 477b8d8684
89 changed files with 196 additions and 171 deletions

View File

@ -1,3 +1,3 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, wait(1)];
export const steps = [{}, wait];

View File

@ -14,7 +14,7 @@ const $await_content = /* @__PURE__ */_._await_content("#text/0", `<!>${$templat
const $try_content__await_promise = /* @__PURE__ */_._await_promise("#text/0");
const $try_content__setup = $scope => {
$await_content($scope);
$try_content__await_promise($scope, resolveAfter(0, 1));
$try_content__await_promise($scope, resolveAfter(0));
};
const $if_content__input_level = /* @__PURE__ */_._if_closure("#text/0", 0, $scope => _._attr($scope["#div/0"], "data-level", $scope._.input_level));
const $if_content__try = /* @__PURE__ */_._try("#text/1", "<!><!><!>", /* over(1), replace, over(2) */"b%c", $try_content__setup);

View File

@ -11,7 +11,7 @@ const $content = input => {
_._try($scope1_id, "#text/1", _._content_resume("__tests__/tags/recurse.marko_2_content", () => {
const $scope2_id = _._scope_id();
const $scope2_reason = _._scope_reason();
_._await($scope2_id, "#text/0", resolveAfter(0, 1), () => {
_._await($scope2_id, "#text/0", resolveAfter(0), () => {
const $scope3_id = _._scope_id();
_._serialize_if($scope0_reason, /* input.level */0) && _._script($scope3_id, "__tests__/tags/recurse.marko_3_input_level");
const $childScope = _._peek_scope_id();
@ -23,12 +23,12 @@ const $content = input => {
_: _._scope_with_id($scope2_id),
"#childScope/0": _._serialize_if($scope0_reason, /* input.level */0) && _._existing_scope($childScope),
"ClosureSignalIndex:input_level": _._serialize_if($scope0_reason, /* input.level */0) && 0
}, "__tests__/tags/recurse.marko", "6:7");
}, "__tests__/tags/recurse.marko", "7:7");
_._resume_branch($scope3_id);
}, _._serialize_guard($scope0_reason, /* input.level */0));
_._serialize_if($scope0_reason, /* input.level */0) && _._scope($scope2_id, {
_: _._scope_with_id($scope1_id)
}, "__tests__/tags/recurse.marko", "4:5");
}, "__tests__/tags/recurse.marko", "5:5");
}, $scope1_id), {
placeholder: _.attrTag({
content: _._content_resume("__tests__/tags/recurse.marko_4_content", () => {
@ -40,7 +40,7 @@ const $content = input => {
_._html(`</div>${_._el_resume($scope1_id, "#div/0", _._serialize_guard($scope0_reason, /* input.level */0))}`);
_._serialize_if($scope0_reason, /* input.level */0) && _._scope($scope1_id, {
_: _._scope_with_id($scope0_id)
}, "__tests__/tags/recurse.marko", "2:1");
}, "__tests__/tags/recurse.marko", "3:1");
return 0;
}
}, $scope0_id, "#text/0", _._serialize_guard($scope0_reason, /* input.level */0), _._serialize_guard($scope0_reason, /* input.level */0), _._serialize_guard($scope0_reason, /* input.level */0), 0, 1);

View File

@ -1,7 +1,8 @@
import { resolveAfter } from "../../../utils/resolve";
if=input.level
div data-level=input.level
try
@placeholder -- LOADING...
await=resolveAfter(0, 1)
await=resolveAfter(0)
recurse level=input.level - 1

View File

@ -1,3 +1,3 @@
import { flush, wait } from "../../utils/resolve";
export const steps = [{}, flush, flush, flush, flush, wait(5)];
export const steps = [{}, flush, flush, flush, flush, wait];

View File

@ -1,5 +1,5 @@
// size: 705 (min) 224 (brotli)
const multiply = (multiplier, n) => resolveAfter(multiplier * n, n),
// size: 703 (min) 222 (brotli)
const multiply = (multiplier, n) => resolveAfter(multiplier * n),
$await_content5__result = _._const(2, ($scope) =>
_._text($scope.a, $scope.c),
),

View File

@ -1,7 +1,7 @@
export const $template = "<button>increment</button><p>1 * <!> = <!></p><p>2 * <!> = <!></p><p>3 * <!> = <!></p><p>4 * <!> = <!></p><p>5 * <!> = <!></p>";
export const $walks = /* get, over(1), next(1), over(1), replace, over(2), replace, out(1), next(1), over(1), replace, over(2), replace, out(1), next(1), over(1), replace, over(2), replace, out(1), next(1), over(1), replace, over(2), replace, out(1), next(1), over(1), replace, over(2), replace, out(1) */" bDb%c%lDb%c%lDb%c%lDb%c%lDb%c%l";
import { resolveAfter } from "../../utils/resolve";
const multiply = (multiplier, n) => resolveAfter(multiplier * n, n);
const multiply = (multiplier, n) => resolveAfter(multiplier * n);
import * as _ from "@marko/runtime-tags/debug/dom";
const $await_content5__result = /* @__PURE__ */_._const("result", $scope => _._text($scope["#text/0"], $scope.result));
const $await_content5__$params = /* @__PURE__ */_._const("$params6", $scope => $await_content5__result($scope, $scope.$params6[0]));

View File

@ -1,5 +1,5 @@
import { resolveAfter } from "../../utils/resolve";
const multiply = (multiplier, n) => resolveAfter(multiplier * n, n);
const multiply = (multiplier, n) => resolveAfter(multiplier * n);
import * as _ from "@marko/runtime-tags/debug/html";
export default _._template("__tests__/template.marko", input => {
const $scope0_id = _._scope_id();

View File

@ -1,5 +1,5 @@
import { resolveAfter } from "../../utils/resolve";
static const multiply = (multiplier, n) => resolveAfter(multiplier * n, n);
static const multiply = (multiplier, n) => resolveAfter(multiplier * n);
<let/n=2>
<button onClick() { n++ }>increment</button>

View File

@ -1,6 +1,6 @@
import { flush, wait } from "../../utils/resolve";
export const steps = [{}, flush, wait(3), click, wait(4)];
export const steps = [{}, flush, wait, click, wait];
export const skip_equivalent = true; // in-order streaming

View File

@ -9,7 +9,7 @@ const $await_content6 = /* @__PURE__ */_._await_content("#text/1", " ", /* get,
const $await_content5__await_promise = /* @__PURE__ */_._await_promise("#text/1", $await_content6__$params);
const $await_content5__setup = $scope => {
$await_content6($scope);
$await_content5__await_promise($scope, resolveAfter("j", 1));
$await_content5__await_promise($scope, resolveAfter("j", 3));
};
const $await_content5__$params = /* @__PURE__ */_._const("$params6", $scope => $await_content5__result($scope, $scope.$params6[0]));
const $await_content4__result = /* @__PURE__ */_._const("result4", $scope => _._text($scope["#text/0"], $scope.result4));
@ -17,7 +17,7 @@ const $await_content5 = /* @__PURE__ */_._await_content("#text/1", "<!><!>k", /*
const $await_content4__await_promise = /* @__PURE__ */_._await_promise("#text/1", $await_content5__$params);
const $await_content4__setup = $scope => {
$await_content5($scope);
$await_content4__await_promise($scope, resolveAfter("i", 1));
$await_content4__await_promise($scope, resolveAfter("i", 2));
};
const $await_content4__$params = /* @__PURE__ */_._const("$params5", $scope => $await_content4__result($scope, $scope.$params5[0]));
const $await_content3__result = /* @__PURE__ */_._const("result3", $scope => _._text($scope["#text/0"], $scope.result3));
@ -27,7 +27,7 @@ const $await_content3 = /* @__PURE__ */_._await_content("#text/1", " ", /* get,
const $await_content2__await_promise = /* @__PURE__ */_._await_promise("#text/1", $await_content3__$params);
const $await_content2__setup = $scope => {
$await_content3($scope);
$await_content2__await_promise($scope, resolveAfter("d", 1));
$await_content2__await_promise($scope, resolveAfter("d", 3));
};
const $await_content2__$params = /* @__PURE__ */_._const("$params3", $scope => $await_content2__result($scope, $scope.$params3[0]));
const $await_content__result = /* @__PURE__ */_._const("result1", $scope => _._text($scope["#text/0"], $scope.result1));
@ -35,7 +35,7 @@ const $await_content2 = /* @__PURE__ */_._await_content("#text/1", "<!><!>e", /*
const $await_content__await_promise = /* @__PURE__ */_._await_promise("#text/1", $await_content2__$params);
const $await_content__setup = $scope => {
$await_content2($scope);
$await_content__await_promise($scope, resolveAfter("c", 1));
$await_content__await_promise($scope, resolveAfter("c", 2));
};
const $await_content__$params = /* @__PURE__ */_._const("$params2", $scope => $await_content__result($scope, $scope.$params2[0]));
const $await_content = /* @__PURE__ */_._await_content("#text/0", "<!><!>f", /* replace, over(1), replace, over(2) */"%b%c", $await_content__setup);

View File

@ -6,10 +6,10 @@ export default _._template("__tests__/template.marko", input => {
_._await($scope0_id, "#text/0", resolveAfter("b", 1), result1 => {
const $scope1_id = _._scope_id();
_._html(_._escape(result1));
_._await($scope1_id, "#text/1", resolveAfter("c", 1), result2 => {
_._await($scope1_id, "#text/1", resolveAfter("c", 2), result2 => {
const $scope2_id = _._scope_id();
_._html(_._escape(result2));
_._await($scope2_id, "#text/1", resolveAfter("d", 1), result3 => {
_._await($scope2_id, "#text/1", resolveAfter("d", 3), result3 => {
const $scope3_id = _._scope_id();
_._html(_._escape(result3));
}, 0);
@ -21,10 +21,10 @@ export default _._template("__tests__/template.marko", input => {
_._await($scope0_id, "#text/1", resolveAfter("h", 1), result4 => {
const $scope4_id = _._scope_id();
_._html(_._escape(result4));
_._await($scope4_id, "#text/1", resolveAfter("i", 1), result5 => {
_._await($scope4_id, "#text/1", resolveAfter("i", 2), result5 => {
const $scope5_id = _._scope_id();
_._html(_._escape(result5));
_._await($scope5_id, "#text/1", resolveAfter("j", 1), result6 => {
_._await($scope5_id, "#text/1", resolveAfter("j", 3), result6 => {
const $scope6_id = _._scope_id();
_._html(_._escape(result6));
}, 0);

View File

@ -2,18 +2,18 @@ import { resolveAfter } from "../../utils/resolve";
-- a
await|result1|=resolveAfter("b", 1)
-- ${result1}
await|result2|=resolveAfter("c", 1)
await|result2|=resolveAfter("c", 2)
-- ${result2}
await|result3|=resolveAfter("d", 1)
await|result3|=resolveAfter("d", 3)
-- ${result3}
-- e
-- f
-- g
await|result4|=resolveAfter("h", 1)
-- ${result4}
await|result5|=resolveAfter("i", 1)
await|result5|=resolveAfter("i", 2)
-- ${result5}
await|result6|=resolveAfter("j", 1)
await|result6|=resolveAfter("j", 3)
-- ${result6}
-- k
-- l

View File

@ -1,5 +1,5 @@
import { flush, wait } from "../../utils/resolve";
export const steps = [{}, flush, flush, flush, wait(4)];
export const steps = [{}, flush, flush, flush, wait];
export const skip_equivalent = true; // in-order streaming

View File

@ -1,6 +1,6 @@
import { flush, wait } from "../../utils/resolve";
export const steps = [{}, flush, flush, wait(4), click];
export const steps = [{}, flush, flush, wait, click];
function click(container: Element) {
container.querySelector("button")!.click();

View File

@ -1,3 +1,3 @@
import { flush, wait } from "../../utils/resolve";
export const steps = [{}, flush, flush, wait(4)];
export const steps = [{}, flush, flush, wait];

View File

@ -1,3 +1,3 @@
import { flush, wait } from "../../utils/resolve";
export const steps = [{}, flush, flush, wait(4)];
export const steps = [{}, flush, flush, wait];

View File

@ -1,5 +1,5 @@
import { flush, wait } from "../../utils/resolve";
export const steps = [{}, flush, flush, wait(3)];
export const steps = [{}, flush, flush, wait];
export const skip_equivalent = true; // in-order streaming

View File

@ -1,5 +1,5 @@
import { flush, wait } from "../../utils/resolve";
export const steps = [{}, flush, wait(3)];
export const steps = [{}, flush, wait];
export const skip_equivalent = true; // in-order streaming

View File

@ -13,7 +13,8 @@
"$$clickCount__script": "a",
"$$clickCount": "i",
"$$clickCount__closure": "l",
"$$try_content__await_promise": "u"
"$$try_content__await_promise": "u",
"$resolveAfterNext": "p"
}
}
}

View File

@ -1,4 +1,4 @@
// size: 307 (min) 191 (brotli)
// size: 305 (min) 190 (brotli)
_._enable_catch();
const $await_content__value = _._const(2, ($scope) =>
_._text($scope.a, $scope.c),
@ -12,7 +12,7 @@ const $try_content__await_promise = _._await_promise(
$await_content__$params,
),
$try_content__clickCount = _._closure_get(2, ($scope) =>
$try_content__await_promise($scope, resolveAfter($scope._.c, 1)),
$try_content__await_promise($scope, resolveAfter($scope._.c)),
),
$clickCount__closure = _._closure($try_content__clickCount),
$clickCount__script = _._script("a1", ($scope) =>

View File

@ -12,7 +12,7 @@ const $try_content__setup = $scope => {
$await_content($scope);
$try_content__clickCount($scope);
};
const $try_content__clickCount = /* @__PURE__ */_._closure_get("clickCount", $scope => $try_content__await_promise($scope, resolveAfter($scope._.clickCount, 1)));
const $try_content__clickCount = /* @__PURE__ */_._closure_get("clickCount", $scope => $try_content__await_promise($scope, resolveAfter($scope._.clickCount)));
const $clickCount__closure = /* @__PURE__ */_._closure($try_content__clickCount);
const $clickCount__script = _._script("__tests__/template.marko_0_clickCount", $scope => _._on($scope["#button/0"], "click", function () {
$clickCount($scope, $scope.clickCount + 1);

View File

@ -7,7 +7,7 @@ export default _._template("__tests__/template.marko", input => {
_._html(`<button>inc</button>${_._el_resume($scope0_id, "#button/0")}`);
_._try($scope0_id, "#text/1", _._content_resume("__tests__/template.marko_1_content", () => {
const $scope1_id = _._scope_id();
_._await($scope1_id, "#text/0", resolveAfter(clickCount, 1), value => {
_._await($scope1_id, "#text/0", resolveAfter(clickCount), value => {
const $scope3_id = _._scope_id();
_._html(`${_._escape(value)}${_._el_resume($scope3_id, "#text/0")}`);
_._scope($scope3_id, {}, "__tests__/template.marko", "7:4");

View File

@ -4,7 +4,7 @@ import { resolveAfter } from "../../utils/resolve";
clickCount++
}>inc</button>
<try>
<await|value|=resolveAfter(clickCount, 1)>
<await|value|=resolveAfter(clickCount)>
${value}
</await>
<@placeholder>

View File

@ -1,6 +1,6 @@
import { flush, wait } from "../../utils/resolve";
export const steps = [{}, flush, wait(1), click, wait(1), click, wait(1)];
export const steps = [{}, flush, wait, click, wait, click, wait];
function click(container: Element) {
container.querySelector("button")!.click();

View File

@ -19,6 +19,6 @@ const $await_promise = /* @__PURE__ */_._await_promise("#text/2");
export function $setup($scope) {
$await_content($scope);
$value($scope, 1);
$await_promise($scope, resolveAfter(0, 3));
$await_promise($scope, resolveAfter(0, 4));
}
export default /* @__PURE__ */_._template("__tests__/template.marko", $template, $walks, $setup);

View File

@ -4,7 +4,7 @@ export default _._template("__tests__/template.marko", input => {
const $scope0_id = _._scope_id();
let value = 1;
_._html(`<button>${_._escape(value)}${_._el_resume($scope0_id, "#text/1")}</button>${_._el_resume($scope0_id, "#button/0")}`);
_._await($scope0_id, "#text/2", resolveAfter(0, 3), () => {
_._await($scope0_id, "#text/2", resolveAfter(0, 4), () => {
const $scope2_id = _._scope_id();
_._html("<span>Hello</span>");
}, 0);

View File

@ -1,7 +1,7 @@
import { resolveAfter } from "../../utils/resolve";
let/value=1
button onClick() { value++ } -- ${value}
await=resolveAfter(0, 3)
await=resolveAfter(0, 4)
span -- Hello
if=value
span -- ${value}

View File

@ -1,13 +1,14 @@
import { flush, wait } from "../../utils/resolve";
import { after, flush } from "../../utils/resolve";
export const steps = [
{},
wait(1),
after(1),
click,
wait(1),
after(2),
click,
wait(1),
after(3),
flush,
after(5),
click,
];

View File

@ -1,3 +1,3 @@
import { flush, wait } from "../../utils/resolve";
export const steps = [{}, flush, wait(1)];
export const steps = [{}, flush, wait];

View File

@ -10,7 +10,6 @@ const $await_content__value__script = _._script("__tests__/template.marko_3_valu
$await_content__value($scope, $scope.value + 1);
}));
const $await_content__value = /* @__PURE__ */_._let("value/3", $scope => {
debugger;
_._text($scope["#text/1"], $scope.value);
$await_content__if($scope, $scope.value > 0 ? 0 : 1);
$if_content__value($scope);

View File

@ -7,7 +7,6 @@ export default _._template("__tests__/template.marko", input => {
_._await($scope1_id, "#text/0", resolveAfter(0, 1), () => {
const $scope3_id = _._scope_id();
let value = 1;
debugger;
_._html(`<button>${_._escape(value)}${_._el_resume($scope3_id, "#text/1")}</button>${_._el_resume($scope3_id, "#button/0")}`);
_._if(() => {
if (value > 0) {
@ -15,7 +14,7 @@ export default _._template("__tests__/template.marko", input => {
_._html(`<span>${_._escape(value)}${_._el_resume($scope4_id, "#text/0")}</span>`);
_._scope($scope4_id, {
_: _._scope_with_id($scope3_id)
}, "__tests__/template.marko", "8:5");
}, "__tests__/template.marko", "7:5");
return 0;
}
}, $scope3_id, "#text/2", 1, /* value */1, /* value */1, 0, 1);

View File

@ -3,7 +3,6 @@ try
@placeholder -- loading...
await=resolveAfter(0, 1)
let/value=1
debug=value
button onClick() { value++ } -- ${value}
if=(value > 0)
span -- ${value}

View File

@ -1,6 +1,6 @@
import { flush, wait } from "../../utils/resolve";
export const steps = [{}, flush, wait(2), click, wait(1), click];
export const steps = [{}, flush, wait, click, wait, click];
function click(container: Element) {
container.querySelector("button")!.click();

View File

@ -10,7 +10,7 @@ const $await_content = /* @__PURE__ */_._await_content("#text/0", "<span> </span
const $try_content__await_promise = /* @__PURE__ */_._await_promise("#text/0");
const $try_content__setup = $scope => {
$await_content($scope);
$try_content__await_promise($scope, resolveAfter(0, 3));
$try_content__await_promise($scope, resolveAfter(0, 4));
};
const $value__closure = /* @__PURE__ */_._closure($await_content__value);
const $value__script = _._script("__tests__/template.marko_0_value", $scope => _._on($scope["#button/0"], "click", function () {

View File

@ -7,7 +7,7 @@ export default _._template("__tests__/template.marko", input => {
_._html(`<button>${_._escape(value)}${_._el_resume($scope0_id, "#text/1")}</button>${_._el_resume($scope0_id, "#button/0")}`);
_._try($scope0_id, "#text/2", _._content_resume("__tests__/template.marko_1_content", () => {
const $scope1_id = _._scope_id();
_._await($scope1_id, "#text/0", resolveAfter(0, 3), () => {
_._await($scope1_id, "#text/0", resolveAfter(0, 4), () => {
const $scope2_id = _._scope_id();
_._script($scope2_id, "__tests__/template.marko_2_value");
_._html(`<span>${_._escape(value)}${_._el_resume($scope2_id, "#text/0")}</span>`);

View File

@ -3,5 +3,5 @@ let/value=1
button onClick() { value++ } -- ${value}
try
@placeholder -- loading...
await=resolveAfter(0, 3)
await=resolveAfter(0, 4)
span -- ${value}

View File

@ -1,13 +1,14 @@
import { flush, wait } from "../../utils/resolve";
import { after, flush } from "../../utils/resolve";
export const steps = [
{},
wait(1),
after(1),
click,
wait(1),
after(2),
click,
wait(1),
after(3),
flush,
after(5),
click,
];

View File

@ -1,5 +1,5 @@
import { flush, wait } from "../../utils/resolve";
export const steps = [{}, wait(1), flush];
export const steps = [{}, wait, flush];
export const skip_equivalent = true; // try removed before flush

View File

@ -1,6 +1,6 @@
import { flush, wait } from "../../utils/resolve";
export const steps = [{}, flush, flush, wait(2), click, click, click];
export const steps = [{}, flush, flush, wait, click, click, click];
export const skip_equivalent = true; // in-order streaming

View File

@ -1,4 +1,4 @@
// size: 454 (min) 233 (brotli)
// size: 452 (min) 233 (brotli)
_._enable_catch();
const $await_content__value__script = _._script(
"a0",
@ -17,7 +17,7 @@ const $try_content__await_promise = _._await_promise(
$await_content__$params,
),
$try_content__value = _._closure_get(3, ($scope) =>
$try_content__await_promise($scope, resolveAfter($scope._.d, 1)),
$try_content__await_promise($scope, resolveAfter($scope._.d)),
),
$value__closure = _._closure($try_content__value),
$value = _._let(3, ($scope) => {

View File

@ -18,7 +18,7 @@ const $try_content__setup = $scope => {
$await_content($scope);
$try_content__value($scope);
};
const $try_content__value = /* @__PURE__ */_._closure_get("value", $scope => $try_content__await_promise($scope, resolveAfter($scope._.value, 1)));
const $try_content__value = /* @__PURE__ */_._closure_get("value", $scope => $try_content__await_promise($scope, resolveAfter($scope._.value)));
const $value__closure = /* @__PURE__ */_._closure($try_content__value);
const $value = /* @__PURE__ */_._let("value/3", $scope => {
_._text($scope["#text/0"], $scope.value);

View File

@ -7,7 +7,7 @@ export default _._template("__tests__/template.marko", input => {
_._html(`<div id=outside>${_._escape(value)}${_._el_resume($scope0_id, "#text/0")}</div>`);
_._try($scope0_id, "#text/1", _._content_resume("__tests__/template.marko_1_content", () => {
const $scope1_id = _._scope_id();
_._await($scope1_id, "#text/0", resolveAfter(value, 1), value => {
_._await($scope1_id, "#text/0", resolveAfter(value), value => {
const $scope3_id = _._scope_id();
_._html(`<div id=inside>${_._escape(value)}${_._el_resume($scope3_id, "#text/0")}</div>`);
_._script($scope3_id, "__tests__/template.marko_3_value");

View File

@ -4,7 +4,7 @@ script -- await resolveAfter(0, 2); value = 1
div#outside -- ${value}
try
@placeholder -- loading...
await|value|=resolveAfter(value, 1)
await|value|=resolveAfter(value)
div#inside -- ${value}
script -- $log().textContent += `\nsetup effect ran`
script -- $log().textContent += `\neffect ran value=${value}`

View File

@ -1,3 +1,3 @@
import { flush, wait } from "../../utils/resolve";
export const steps = [{}, flush, wait(2), wait(2)];
export const steps = [{}, flush, wait];

View File

@ -1,4 +1,4 @@
// size: 452 (min) 232 (brotli)
// size: 454 (min) 232 (brotli)
_._enable_catch();
const $await_content__value__script = _._script(
"a0",
@ -17,7 +17,7 @@ const $try_content__await_promise = _._await_promise(
$await_content__$params,
),
$try_content__value = _._closure_get(3, ($scope) =>
$try_content__await_promise($scope, resolveAfter($scope._.d, 2)),
$try_content__await_promise($scope, resolveAfter($scope._.d, 3)),
),
$value__closure = _._closure($try_content__value),
$value = _._let(3, ($scope) => {
@ -25,7 +25,7 @@ const $try_content__await_promise = _._await_promise(
});
(_._script("a3", ($scope) =>
(async () => {
(await resolveAfter(1), $value($scope, 1));
(await resolveAfter(0, 1), $value($scope, 1));
})(),
),
init());

View File

@ -18,7 +18,7 @@ const $try_content__setup = $scope => {
$await_content($scope);
$try_content__value($scope);
};
const $try_content__value = /* @__PURE__ */_._closure_get("value", $scope => $try_content__await_promise($scope, resolveAfter($scope._.value, 2)));
const $try_content__value = /* @__PURE__ */_._closure_get("value", $scope => $try_content__await_promise($scope, resolveAfter($scope._.value, 3)));
const $value__closure = /* @__PURE__ */_._closure($try_content__value);
const $value = /* @__PURE__ */_._let("value/3", $scope => {
_._text($scope["#text/0"], $scope.value);
@ -26,7 +26,7 @@ const $value = /* @__PURE__ */_._let("value/3", $scope => {
});
const $try = /* @__PURE__ */_._try("#text/1", "<!><!><!>", /* over(1), replace, over(2) */"b%c", $try_content__setup);
const $setup__script = _._script("__tests__/template.marko_0", $scope => (async () => {
await resolveAfter(1);
await resolveAfter(0, 1);
$value($scope, 1);
})());
export function $setup($scope) {

View File

@ -7,7 +7,7 @@ export default _._template("__tests__/template.marko", input => {
_._html(`<div id=outside>${_._escape(value)}${_._el_resume($scope0_id, "#text/0")}</div>`);
_._try($scope0_id, "#text/1", _._content_resume("__tests__/template.marko_1_content", () => {
const $scope1_id = _._scope_id();
_._await($scope1_id, "#text/0", resolveAfter(value, 2), value => {
_._await($scope1_id, "#text/0", resolveAfter(value, 3), value => {
const $scope3_id = _._scope_id();
_._html(`<div id=inside>${_._escape(value)}${_._el_resume($scope3_id, "#text/0")}</div>`);
_._script($scope3_id, "__tests__/template.marko_3_value");

View File

@ -1,10 +1,10 @@
import { resolveAfter } from "../../utils/resolve";
let/value=0
script -- await resolveAfter(1); value = 1
script -- await resolveAfter(0, 1); value = 1
div#outside -- ${value}
try
@placeholder -- loading...
await|value|=resolveAfter(value, 2)
await|value|=resolveAfter(value, 3)
div#inside -- ${value}
script -- $log().textContent += `\nsetup effect ran`
script -- $log().textContent += `\neffect ran value=${value}`

View File

@ -1,3 +1,3 @@
import { flush, wait } from "../../utils/resolve";
import { after, flush, wait } from "../../utils/resolve";
export const steps = [{}, wait(1), flush, wait(2)];
export const steps = [{}, after(2), flush, wait];

View File

@ -1,5 +1,5 @@
import { flush, wait } from "../../utils/resolve";
export const steps = [{}, flush, wait(2)];
export const steps = [{}, flush, wait];
export const skip_equivalent = true; // in-order streaming

View File

@ -1,5 +1,5 @@
import { flush, wait } from "../../utils/resolve";
export const steps = [{}, flush, wait(2)];
export const steps = [{}, flush, wait];
export const skip_equivalent = true; // in-order streaming

View File

@ -1,3 +1,3 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, wait(1)];
export const steps = [{}, wait];

View File

@ -1,3 +1,3 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, wait(1)];
export const steps = [{}, wait];

View File

@ -1,3 +1,3 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, wait(1)];
export const steps = [{}, wait];

View File

@ -1,4 +1,4 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, wait(2)];
export const steps = [{}, wait];
export const error_runtime = true;

View File

@ -1,3 +1,3 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, wait(1)];
export const steps = [{}, wait];

View File

@ -1,3 +1,3 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, wait(1)];
export const steps = [{}, wait];

View File

@ -1,3 +1,3 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, wait(1)];
export const steps = [{}, wait];

View File

@ -1,3 +1,3 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, wait(1)];
export const steps = [{}, wait];

View File

@ -1,3 +1,3 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, wait(1)];
export const steps = [{}, wait];

View File

@ -1,3 +1,3 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, wait(1)];
export const steps = [{}, wait];

View File

@ -7,5 +7,5 @@ export const steps = [
serializedGlobals: { cspNonce: true },
},
},
wait(1),
wait,
];

View File

@ -7,5 +7,5 @@ export const steps = [
serializedGlobals: { cspNonce: true },
},
},
wait(1),
wait,
];

View File

@ -1,3 +1,3 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, wait(1)];
export const steps = [{}, wait];

View File

@ -1,3 +1,3 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, wait(1)];
export const steps = [{}, wait];

View File

@ -1,3 +1,3 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, wait(1)];
export const steps = [{}, wait];

View File

@ -1,6 +1,6 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, increment, increment, wait(1)];
export const steps = [{}, increment, increment, wait];
function increment(container: Element) {
container.querySelector<HTMLButtonElement>("#increment")?.click();

View File

@ -1,3 +1,3 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, wait(1)];
export const steps = [{}, wait];

View File

@ -1,3 +1,3 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, wait(1)];
export const steps = [{}, wait];

View File

@ -1,5 +1,5 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, wait(1)];
export const steps = [{}, wait];
export const skip_equivalent = true;

View File

@ -1,3 +1,3 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, wait(1)];
export const steps = [{}, wait];

View File

@ -1,3 +1,3 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, wait(1)];
export const steps = [{}, wait];

View File

@ -1,5 +1,5 @@
import { flush, wait } from "../../utils/resolve";
export const steps = [{}, flush, flush, wait(2)];
export const steps = [{}, flush, flush, wait];
export const skip_equivalent = true; // in-order streaming

View File

@ -1,5 +1,5 @@
import { flush, wait } from "../../utils/resolve";
export const steps = [{}, flush, wait(1)];
export const steps = [{}, flush, wait];
export const skip_equivalent = true; // in-order streaming

View File

@ -1,3 +1,3 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, wait(1)];
export const steps = [{}, wait];

View File

@ -1,5 +1,5 @@
import { flush, wait } from "../../utils/resolve";
export const steps = [{}, flush, flush, flush, wait(4)];
export const steps = [{}, flush, flush, flush, wait];
export const skip_equivalent = true; // in-order streaming

View File

@ -1,3 +1,3 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, wait(1)];
export const steps = [{}, wait];

View File

@ -1,3 +1,3 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, wait(1)];
export const steps = [{}, wait];

View File

@ -1,3 +1,3 @@
import { wait } from "../../utils/resolve";
export const steps = [{}, wait(2)];
export const steps = [{}, wait];

View File

@ -1,4 +1,4 @@
// size: 501 (min) 284 (brotli)
// size: 499 (min) 285 (brotli)
_._enable_catch();
const $await_content__value = _._const(2, ($scope) =>
_._text(
@ -28,7 +28,7 @@ const $try_content__await_promise = _._await_promise(
($scope) => ($scope._.b.textContent = $scope._.d),
),
$try_content__clickCount = _._closure_get(3, ($scope) => {
($try_content__await_promise($scope, resolveAfter($scope._.d, 1)),
($try_content__await_promise($scope, resolveAfter($scope._.d)),
$try_content__clickCount__script($scope));
}),
$clickCount__closure = _._closure($try_content__clickCount),

View File

@ -15,7 +15,7 @@ const $await_content = /* @__PURE__ */_._await_content("#text/0", "Async: <!>",
const $try_content__await_promise = /* @__PURE__ */_._await_promise("#text/0", $await_content__$params);
const $try_content__clickCount__script = _._script("__tests__/template.marko_1_clickCount", $scope => (_._el_read($scope._["#div/1"]).textContent = $scope._.clickCount));
const $try_content__clickCount = /* @__PURE__ */_._closure_get("clickCount", $scope => {
$try_content__await_promise($scope, resolveAfter($scope._.clickCount, 1));
$try_content__await_promise($scope, resolveAfter($scope._.clickCount));
$try_content__clickCount__script($scope);
});
const $try_content__setup = $scope => {

View File

@ -7,7 +7,7 @@ export default _._template("__tests__/template.marko", input => {
_._html(`<button>inc</button>${_._el_resume($scope0_id, "#button/0")}<div></div>${_._el_resume($scope0_id, "#div/1")}`);
_._try($scope0_id, "#text/2", _._content_resume("__tests__/template.marko_1_content", () => {
const $scope1_id = _._scope_id();
_._await($scope1_id, "#text/0", resolveAfter(clickCount, 1), value => {
_._await($scope1_id, "#text/0", resolveAfter(clickCount), value => {
const $scope4_id = _._scope_id();
_._html(`Async: <!>${_._escape(value > 1 ? (() => {
throw new Error("ERROR!");

View File

@ -8,7 +8,7 @@ import { resolveAfter } from "../../utils/resolve";
<script>
el().textContent = clickCount;
</script>
<await|value|=resolveAfter(clickCount, 1)>
<await|value|=resolveAfter(clickCount)>
Async: ${value > 1 ? (() => { throw new Error("ERROR!")})() : value}
</await>
<@placeholder>

View File

@ -1,6 +1,6 @@
import { flush, wait } from "../../utils/resolve";
export const steps = [{}, flush, wait(1), click, wait(1), click, wait(1)];
export const steps = [{}, flush, wait, click, wait, click, wait];
function click(container: Element) {
container.querySelector("button")!.click();

View File

@ -1,2 +1,3 @@
import { wait } from "../../utils/resolve";
export const steps = [{ value: 0 }, wait(4), { value: 1 }, wait(4)] as const;
export const steps = [{ value: 0 }, wait, { value: 1 }, wait];

View File

@ -11,7 +11,13 @@ import { isDeepStrictEqual } from "util";
import * as translator from "../translator";
import { bundle } from "./utils/bundle";
import createBrowser from "./utils/create-browser";
import { isFlush, isThrows, isWait, resolveAfter } from "./utils/resolve";
import {
isFlush,
isThrows,
isWait,
resetResolveState,
resolveAfter,
} from "./utils/resolve";
import { stripInlineRuntime } from "./utils/strip-inline-runtime";
import createMutationTracker from "./utils/track-mutations";
@ -435,6 +441,10 @@ describe("runtime-tags/translator", () => {
});
describe("render", () => {
beforeEach(() => {
resetResolveState();
});
(skipSSR ? it.skip : it)("ssr", async () => {
await snapMD(async () => (await ssr()).tracker.getLogs());
});
@ -526,32 +536,6 @@ describe("runtime-tags/translator", () => {
} else {
assert.strictEqual(actual, expected);
}
// // when the steps for a test contains more than one input,
// // the updates are not run for the resume test
// // so we trim the csrLogs to match the number of resumeLogs
// const step1 = (config.steps as unknown[] | undefined)?.[1];
// const isAsyncRender = step1 && (isFlush(step1) || isWait(step1));
// let csrLogs = [...(await csr()).tracker.getRawLogs(true)];
// let skip = 0;
// if (isAsyncRender) {
// while (csrLogs[skip + 1]?.startsWith(`# Render ASYNC`)) {
// skip++;
// }
// for (const resumeLog of resumeLogs.slice(1)) {
// if (resumeLog.startsWith(`# Render ASYNC`)) {
// skip--;
// } else {
// break;
// }
// }
// csrLogs[skip] = csrLogs[skip].replace(`# Render ASYNC`, `# Render`);
// }
// csrLogs = csrLogs.slice(skip, resumeLogs.length + skip);
// assert.strictEqual(
// csrLogs.join("\n\n").replace(/[cs]M_[a-z0-9]+/g, "%id"),
// resumeLogs.join("\n\n").replace(/[cs]M_[a-z0-9]+/g, "%id"),
// );
});
});
});

View File

@ -6,8 +6,10 @@ export default function (options: Parameters<typeof createBrowser>[0]) {
stream(chunks: string[]): () => boolean;
};
const window = browser.window as unknown as DOMWindow & {
__RESOLVE_STATE__: typeof globalThis.__RESOLVE_STATE__;
MessageChannel: any;
};
window.__RESOLVE_STATE__ = globalThis.__RESOLVE_STATE__;
window.MARKO_DEBUG = true;
window.MessageChannel = (window as any).MessageChannel =
class MessageChannel {

View File

@ -1,10 +1,45 @@
const TIMEOUT_MULTIPLIER = 50;
const promisesByResolveTime = new Map<number, Promise<any>>();
declare global {
var __RESOLVE_STATE__: {
lastId: number;
promises: Map<number, Promise<number>>;
};
}
export function wait(timeout: number) {
return Object.assign(() => resolveAfter(`wait:${timeout}`, timeout), {
const state = (globalThis.__RESOLVE_STATE__ ||= {
lastId: 0,
promises: new Map(),
});
export function resetResolveState() {
state.lastId = 0;
state.promises = new Map();
}
export const wait = Object.assign(
async () => {
let id: number;
let nextId: number | undefined;
do {
id = await getSharedPromise(nextId);
await new Promise((r) => setImmediate(r));
nextId = state.promises.size;
} while (id !== nextId);
},
{
wait: true,
});
},
);
export function after(id: number) {
return Object.assign(
async () => {
await getSharedPromise(id);
await new Promise((r) => setImmediate(r));
},
{
wait: true,
},
);
}
export const flush = Object.assign(() => {}, {
@ -15,11 +50,11 @@ export function throws(fn: (...args: any[]) => void) {
return Object.assign(fn, { throws: true });
}
export function isWait(value: any): value is ReturnType<typeof wait> {
export function isWait(value: any): value is typeof wait {
return typeof value === "function" && value.wait;
}
export function isFlush(value: any): value is ReturnType<typeof flush> {
export function isFlush(value: any): value is typeof flush {
return typeof value === "function" && value.flush;
}
@ -27,16 +62,17 @@ export function isThrows(value: any): value is ReturnType<typeof throws> {
return typeof value === "function" && value.throws;
}
export function resolveAfter<T>(value: T, timeout: number) {
const promise = getSharedPromise(timeout);
export function resolveAfter<T>(value: T, id?: number) {
const promise = getSharedPromise(id);
return Object.assign(
promise.then(() => value),
promise.then(() => {
return value;
}),
{ value },
);
}
export function rejectAfter<T extends Error>(value: T, timeout: number) {
const promise = getSharedPromise(timeout);
export function rejectAfter<T extends Error>(value: T, id?: number) {
const promise = getSharedPromise(id);
return Object.assign(
promise.then(() => {
throw value;
@ -45,25 +81,26 @@ export function rejectAfter<T extends Error>(value: T, timeout: number) {
);
}
function getSharedPromise(timeout: number) {
const resolveTime = roundToNearestTimeBucket(
Date.now() + timeout * TIMEOUT_MULTIPLIER,
);
let resolvePromise = promisesByResolveTime.get(resolveTime);
if (!resolvePromise) {
resolvePromise = new Promise<undefined>((resolve) =>
setTimeout(() => {
promisesByResolveTime.delete(resolveTime);
resolve(undefined);
}, timeout * TIMEOUT_MULTIPLIER),
);
promisesByResolveTime.set(resolveTime, resolvePromise);
function getSharedPromise(id: number = state.lastId + 1): Promise<number> {
if (id < 1) {
return Promise.resolve(0);
}
return resolvePromise;
let promise = state.promises.get(id);
if (!promise) {
state.promises.set(id, (promise = getSharedPromise(id - 1).then(tick)));
}
return promise;
}
function roundToNearestTimeBucket(time: number) {
return Math.round(time / TIMEOUT_MULTIPLIER) * TIMEOUT_MULTIPLIER;
function tick() {
return new Promise<number>((r) => {
setTimeout(() => {
setImmediate(() => {
setTimeout(() => {
r(++state.lastId);
});
});
});
});
}