<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Verify that setTimeout tasks can be properly tracked.</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/task-ids.js"></script>
</head>
<body>
<script>
promise_test(() => {
return new Promise(async (resolve, reject) => {
const initialId = initializeTaskId();
await new Promise(resolve => setTimeout(resolve, 0));
queueMicrotask(() => {
try {
assert_equals(scheduler.taskId, initialId);
resolve();
} catch {
reject("Not an ancestor");
}
});
});
}, "An immediate setTimeout microtask is a descendant of the dispatching task");
promise_test(() => {
return new Promise(async (resolve, reject) => {
const initialId = initializeTaskId();
await new Promise(internal_resolve => {
window.resolve = internal_resolve;
setTimeout("resolve()", 100);
});
queueMicrotask(() => {
try {
assert_equals(scheduler.taskId, initialId);
resolve();
} catch {
reject("Not an ancestor");
}
});
});
}, "A microtask queued after a long setTimeout task with text input is a " +
"descendant of the dispatching task");
promise_test(async () => {
window.initialId = scheduler.taskId;
await new Promise((resolve, reject) => {
window.resolve = resolve;
window.reject = reject;
setTimeout(`
try {
assert_equals(scheduler.taskId, initialId);
resolve();
} catch {
reject("Not an ancestor");
}`, 100);
});
}, "A long setTimeout task with text input is a descendant of the dispatching task");
promise_test(() => {
return new Promise(async (resolve, reject) => {
const initialId = initializeTaskId();
await new Promise(resolve => setTimeout(resolve, 100));
queueMicrotask(() => {
try {
assert_equals(scheduler.taskId, initialId);
resolve();
} catch {
reject("Not an ancestor");
}
});
});
}, "A long setTimeout microtask is a descendant of the dispatching task");
promise_test(async () => {
const initialId = initializeTaskId();
await new Promise((resolve, reject) => setTimeout(() => {
try {
assert_equals(scheduler.taskId, initialId);
resolve();
} catch {
reject("Initial task not identified as ancestor of first setTimeout");
}
resolve();
}, 10));
await new Promise((resolve, reject) => setTimeout(() => {
try {
assert_equals(scheduler.taskId, initialId);
resolve();
} catch {
reject("Initial task not identified as ancestor of second setTimeout");
}
}, 10));
}, "An async chain of setTimeouts task properly track their ancestors");
promise_test(async () => {
const initialId = initializeTaskId();
return new Promise((resolve, reject) => {
try {
assert_equals(scheduler.taskId, initialId);
resolve();
} catch {
reject("The task is not its own ancestor");
}
});
}, "A task is its own ancestor");
promise_test(async t => {
let firstTaskParent;
let firstTaskDescendent;
const initialId = initializeTaskId();
const first = new Promise((resolve, reject) => setTimeout(t.step_func(() => {
assert_equals(scheduler.taskId, initialId);
firstTaskParent = initializeTaskId();
setTimeout(t.step_func(() => {
firstTaskDescendent = scheduler.taskId;
assert_equals(firstTaskDescendent, firstTaskParent);
assert_not_equals(firstTaskDescendent, initialId);
resolve();
}), 0);
}), 15));
const second = new Promise((resolve, reject) => setTimeout(t.step_func(() => {
assert_equals(scheduler.taskId, initialId);
const secondTaskParent = initializeTaskId();
setTimeout(t.step_func(() => {
try {
assert_equals(scheduler.taskId, secondTaskParent);
assert_not_equals(scheduler.taskId, firstTaskDescendent);
assert_not_equals(scheduler.taskId, initialId);
resolve();
} catch (e) {
reject(e);
}
}), 0);
}), 30));
await Promise.all([first, second]);
}, "Two unrelated setTimeout tasks properly track their ancestors");
promise_test(async t => {
window.initialId = initializeTaskId();
const first = new Promise((resolve, reject) => setTimeout(t.step_func(() => {
assert_equals(scheduler.taskId, initialId);
window.firstTaskParent = initializeTaskId();
window.resolve1 = resolve;
window.reject1 = reject;
setTimeout(`
try {
window.firstTaskDescendent = scheduler.taskId;
assert_equals(window.firstTaskDescendent, firstTaskParent);
assert_not_equals(window.firstTaskDescendent, initialId);
resolve1();
} catch {
reject1("Initial task not identified as ancestor of first setTimeout");
}
`, 0);
}), 15));
const second = new Promise((resolve, reject) => setTimeout(t.step_func(() => {
window.resolve2 = resolve;
window.reject2 = reject;
assert_equals(scheduler.taskId, initialId);
window.secondTaskParent = initializeTaskId();
setTimeout(`
try {
assert_equals(scheduler.taskId, window.secondTaskParent);
assert_not_equals(scheduler.taskId, window.firstTaskDescendent);
assert_not_equals(scheduler.taskId, window.initialId);
resolve2();
} catch {
reject2("Initial task not identified as ancestor of second setTimeout");
}
`, 0);
}), 30));
await Promise.all([first, second]);
}, "Two unrelated setTimeout tasks (delivered as strings) properly track their ancestors");
promise_test(async t => {
const initialId = initializeTaskId();
let times = 0;
const ITERATIONS = 15;
await new Promise((resolve, reject) => setTimeout(t.step_func(() => {
const timeout = () => {
assert_equals(scheduler.taskId, initialId);
if (++times < ITERATIONS) {
setTimeout(t.step_func(timeout), 0);
} else {
resolve();
}
};
setTimeout(t.step_func(timeout), 0);
}), 0));
}, "Recursive setTimeout");
</script>
</body>
</html>