about summary refs log tree commit diff stats
path: root/test/js
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-04-21 21:26:27 +0200
committerbptato <nincsnevem662@gmail.com>2024-04-21 21:28:45 +0200
commite3d9ee2c6224cd30bf56e24f7988899e0e3985c1 (patch)
tree31116d7d751d058f32bf43313c12673423e8d8be /test/js
parentba88f015ea500bcc574b621392c721ef2c9dbcd0 (diff)
downloadchawan-e3d9ee2c6224cd30bf56e24f7988899e0e3985c1.tar.gz
test: add js & layout tests
(Sadly some layout tests still fail.)
Diffstat (limited to 'test/js')
-rw-r--r--test/js/all.expected1
-rw-r--r--test/js/array_proto_at.html9
-rw-r--r--test/js/asserts.js19
-rw-r--r--test/js/base64.html44
-rw-r--r--test/js/class.html23
-rw-r--r--test/js/config.toml13
-rw-r--r--test/js/console.html5
-rw-r--r--test/js/data_url.html4
-rw-r--r--test/js/date.html14
-rw-r--r--test/js/document.html11
-rw-r--r--test/js/documentall.html19
-rw-r--r--test/js/docwrite1.html101
-rw-r--r--test/js/docwrite2.html31
-rw-r--r--test/js/docwrite3.html43
-rw-r--r--test/js/docwrite4.html49
-rw-r--r--test/js/encode_decode.html39
-rw-r--r--test/js/htmlcollection.html22
-rw-r--r--test/js/outerhtml.html9
-rw-r--r--test/js/prev_next_parent_child.html22
-rw-r--r--test/js/query_selector_plus.html11
-rw-r--r--test/js/reflect.html18
-rwxr-xr-xtest/js/run_js_tests.sh13
-rw-r--r--test/js/settimeout.html8
-rw-r--r--test/js/template.html8
-rw-r--r--test/js/text.html8
-rw-r--r--test/js/window.html11
26 files changed, 555 insertions, 0 deletions
diff --git a/test/js/all.expected b/test/js/all.expected
new file mode 100644
index 00000000..35821117
--- /dev/null
+++ b/test/js/all.expected
@@ -0,0 +1 @@
+Success
diff --git a/test/js/array_proto_at.html b/test/js/array_proto_at.html
new file mode 100644
index 00000000..844aa563
--- /dev/null
+++ b/test/js/array_proto_at.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<div id=x>Fail</div>
+<script src=asserts.js></script>
+<script>
+assert(!![].at);
+assert_equals([1, 2, 3].at(-2), 2);
+assert_equals([1, 2, 3].at(-4), undefined);
+document.getElementById("x").textContent = "Success";
+</script>
diff --git a/test/js/asserts.js b/test/js/asserts.js
new file mode 100644
index 00000000..4d8fd62c
--- /dev/null
+++ b/test/js/asserts.js
@@ -0,0 +1,19 @@
+function assert(x, msg) {
+	const mymsg = msg ? ": " + msg : "";
+	if (!x)
+		throw new TypeError("Assertion failed" + mymsg);
+}
+
+function assert_throws(expr, error) {
+	try {
+		eval(expr);
+	} catch (e) {
+		if (e instanceof error)
+			return;
+	}
+	throw new TypeError("Assertion failed");
+}
+
+function assert_equals(a, b) {
+	assert(a === b, "Expected " + b + " but got " + a);
+}
diff --git a/test/js/base64.html b/test/js/base64.html
new file mode 100644
index 00000000..0573d477
--- /dev/null
+++ b/test/js/base64.html
@@ -0,0 +1,44 @@
+<!doctype html>
+<title>base64 test</title>
+<div id=x>Fail</div>
+<script src=asserts.js></script>
+<script>
+
+const div = document.getElementById("x");
+assert_equals(atob(""), "");
+assert_equals(atob(" "), "");
+assert_equals(atob("YQ"), "a");
+assert_equals(atob("YR"), "a");
+assert_throws('atob("!")', DOMException);
+assert_throws('atob("a")', DOMException);
+assert_throws('atob("aaaaa")', DOMException);
+assert_throws('atob("Aaa==")', DOMException);
+assert_throws('atob("Aaaa==")', DOMException);
+assert_throws('atob("Aaaaa==")', DOMException);
+assert_throws('atob("Aa aaa= = ")', DOMException);
+assert_equals(atob("AAAAAA=="), atob("AAAAAA"));
+assert_equals(atob("AAAAAA"), atob("A A A A A A"));
+assert_equals(atob("AAAAAA"), "\u0000\u0000\u0000\u0000");
+assert_equals(atob("ABCDEF"), "\u0000\u0010\u0083\u0010");
+assert_equals(atob("//////"), "ÿÿÿÿ");
+const longa =
+	"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz" +
+	"IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg" +
+	"dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu" +
+	"dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo" +
+	"ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4K";
+const longb = "Man is distinguished, not only by his reason, but by this " +
+	"singular passion from other animals, which is a lust of the mind, " +
+	"that by a perseverance of delight in the continued and " +
+	"indefatigable generation of knowledge, exceeds the short vehemence " +
+	"of any carnal pleasure.\n";
+assert_equals(atob(longa), longb);
+assert_equals(btoa(""), "");
+assert_equals(btoa("a"), "YQ==");
+assert_equals(btoa("aa"), "YWE=");
+assert_equals(btoa("aaa"), "YWFh");
+assert_equals(btoa("aaazdxfksljdf"), "YWFhemR4ZmtzbGpkZg==");
+assert_equals(btoa(longb), longa);
+assert_throws('btoa("őÉéeé")', DOMException);
+div.textContent = "Success";
+</script>
diff --git a/test/js/class.html b/test/js/class.html
new file mode 100644
index 00000000..7c14049e
--- /dev/null
+++ b/test/js/class.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<title>Element class test</title>
+<div class="a b c">Fail</div>
+<script>
+(function() {
+	let div = document.getElementsByClassName("a")[0]
+	const classes = ["a", "b", "c"];
+	let cl = div.classList;
+	for (let i = 0; i < classes.length; ++i) {
+		if (cl[i] !== classes[i])
+			return;
+	}
+	const classes2 = ["x", "y", "z"];
+	div.setAttribute("class", classes2.join(' '));
+	let i = 0;
+	for (let x of cl) {
+		if (x != classes2[i])
+			return;
+		++i;
+	}
+	div.textContent = "Success";
+})();
+</script>
diff --git a/test/js/config.toml b/test/js/config.toml
new file mode 100644
index 00000000..32cb3cd0
--- /dev/null
+++ b/test/js/config.toml
@@ -0,0 +1,13 @@
+[[siteconf]]
+match = "file:///.*"
+scripting = true
+
+[display]
+columns = 80
+lines = 24
+pixels-per-column = 9
+pixels-per-line = 18
+force-columns = true
+force-lines = true
+force-pixels-per-column = true
+force-pixels-per-line = true
diff --git a/test/js/console.html b/test/js/console.html
new file mode 100644
index 00000000..67b244a7
--- /dev/null
+++ b/test/js/console.html
@@ -0,0 +1,5 @@
+<!doctype html>
+<div>Success</div>
+<script>
+console.log("Hello, world!")
+</script>
diff --git a/test/js/data_url.html b/test/js/data_url.html
new file mode 100644
index 00000000..5da3f920
--- /dev/null
+++ b/test/js/data_url.html
@@ -0,0 +1,4 @@
+<!DOCTYPE html>
+<div id=abc>Fail</div>
+<script src="data:text/javascript,document.getElementById('abc').textContent='Success'">
+</script>
diff --git a/test/js/date.html b/test/js/date.html
new file mode 100644
index 00000000..86a2818b
--- /dev/null
+++ b/test/js/date.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<!--
+Test for whether the Date constructor works at all.
+QuickJS uses some syscalls and library calls for this, and sandboxing
+sometimes isn't very cooperative in this regard.
+-->
+<title>Date constructor test</title>
+<div id=x>Fail</div>
+<script>
+(function() {
+	new Date();
+	document.getElementById("x").textContent = "Success";
+})();
+</script>
diff --git a/test/js/document.html b/test/js/document.html
new file mode 100644
index 00000000..26dfa528
--- /dev/null
+++ b/test/js/document.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<title>Window test</title>
+<div id="abc">Fail</div>
+<script>
+(function() {
+	if (document.toString() !== "[object Document]") return;
+	if (document !== window.document) return;
+	if (document.implementation !== document.implementation) return;
+	document.getElementById("abc").textContent = "Success";
+})()
+</script>
diff --git a/test/js/documentall.html b/test/js/documentall.html
new file mode 100644
index 00000000..14db9d70
--- /dev/null
+++ b/test/js/documentall.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>HTMLCollection test</title>
+<div id="result">Fail</div>
+<style>style 1</style>
+<style>style 2</style>
+<style>style 3</style>
+<script>
+(function() {
+	const abc = document.all;
+	if (document.all || abc) return; /* document.all must be falsy */
+	if (abc.length !== 9) return;
+	const styles = [abc[5], abc[6], abc[7]];
+	if (styles[0].textContent !== "style 1") return;
+	if (styles[1].textContent !== "style 2") return;
+	if (styles[2].textContent !== "style 3") return;
+	const result = document.getElementById("result");
+	result.textContent = "Success";
+})()
+</script>
diff --git a/test/js/docwrite1.html b/test/js/docwrite1.html
new file mode 100644
index 00000000..bc7f8882
--- /dev/null
+++ b/test/js/docwrite1.html
@@ -0,0 +1,101 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>document.write test</title>
+<script>
+window.onload = function() {
+	const success = document.body.innerHTML == document.querySelector("style").textContent;
+	while (document.body.childNodes[0])
+		document.body.childNodes[0].remove();
+	document.body.innerHTML = success ? "Success" : "Fail";
+}
+let checkpointCounter = 0;
+function checkpoint(n) {
+	if (++checkpointCounter != n)
+		throw new TypeError(`Checkpoint failed: expected ${n} but got ${checkpointCounter}`);
+}
+</script>
+<style><h1>Main title</h1>
+
+
+<p>Text.</p>
+<script>
+document.write(`<h2>Subtitle</h2>
+<script>
+checkpoint(1);
+</scr` + `ipt>
+`);
+
+checkpoint(2);
+
+document.write(`
+<script>
+checkpoint(3);
+document.write(
+'<p>before subtext</p>\\n' +
+'<script>\\n' +
+'checkpoint(4);\\n' +
+'document.write("third nest");\\n' +
+'</scr' + 'ipt>\\n'
+);
+</scr` + `ipt>
+<p>fin</p>
+`);
+</script><h2>Subtitle</h2>
+<script>
+checkpoint(1);
+</script>
+
+<script>
+checkpoint(3);
+document.write(
+'<p>before subtext</p>\n' +
+'<script>\n' +
+'checkpoint(4);\n' +
+'document.write("third nest");\n' +
+'</scr' + 'ipt>\n'
+);
+</script><p>before subtext</p>
+<script>
+checkpoint(4);
+document.write("third nest");
+</script>third nest
+
+<p>fin</p>
+
+<p>Subtext.</p>
+
+
+</style>
+<script>
+document.write("<h1>Main title</h1>");
+</script>
+</head>
+<body>
+<p>Text.</p>
+<script>
+document.write(`<h2>Subtitle</h2>
+<script>
+checkpoint(1);
+</scr` + `ipt>
+`);
+
+checkpoint(2);
+
+document.write(`
+<script>
+checkpoint(3);
+document.write(
+'<p>before subtext</p>\\n' +
+'<script>\\n' +
+'checkpoint(4);\\n' +
+'document.write("third nest");\\n' +
+'</scr' + 'ipt>\\n'
+);
+</scr` + `ipt>
+<p>fin</p>
+`);
+</script>
+<p>Subtext.</p>
+</body>
+</html>
diff --git a/test/js/docwrite2.html b/test/js/docwrite2.html
new file mode 100644
index 00000000..876f3cdd
--- /dev/null
+++ b/test/js/docwrite2.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>document.write test</title>
+<script>
+window.onload = function() {
+	const success = document.body.innerHTML == document.querySelector("style").textContent;
+	while (document.body.childNodes[0])
+		document.body.childNodes[0].remove();
+	document.body.innerHTML = success ? "Success" : "Fail";
+}
+let checkpointCounter = 0;
+function checkpoint(n) {
+	if (++checkpointCounter != n)
+		throw new TypeError(`Checkpoint failed: expected ${n} but got ${checkpointCounter}`);
+}
+</script>
+<style><script>
+document.write("a");
+document.write("<script></scr" + "ipt>x");
+document.write("t");
+</script>a<script></script>xt
+
+</style>
+</head>
+<body><script>
+document.write("a");
+document.write("<script></scr" + "ipt>x");
+document.write("t");
+</script></body>
+</html>
diff --git a/test/js/docwrite3.html b/test/js/docwrite3.html
new file mode 100644
index 00000000..24fc2222
--- /dev/null
+++ b/test/js/docwrite3.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<script>
+window.onload = function() {
+	const success = document.body.outerHTML == document.querySelector("style").textContent;
+	/*
+	console.log("BODY", document.body.outerHTML)
+	console.log("STYLE", document.querySelector("style").textContent)
+	*/
+	while (document.body.childNodes[0])
+		document.body.childNodes[0].remove();
+	document.body.innerHTML = success ? "Success" : "Fail";
+}
+</script>
+<style><body><h1>Main title</h1>
+
+
+<p>Text.</p>
+<script>
+document.write("<h2>Subtitle</h2>");
+document.write("<scr" + "ipt>document.write('<p>before subtext</p><scri'+'pt>document.write(`third nest`)</scri'+'pt>')</scrip" + "t><p>fin</p>");
+</script><h2>Subtitle</h2><script>document.write('<p>before subtext</p><scri'+'pt>document.write(`third nest`)</scri'+'pt>')</script><p>before subtext</p><script>document.write(`third nest`)</script>third nest<p>fin</p>
+<p>Subtext.</p>
+
+
+
+</body></style>
+<title>Write example</title>
+<script>
+document.write("<h1>Main title</h1>");
+</script>
+</head>
+<body>
+<p>Text.</p>
+<script>
+document.write("<h2>Subtitle</h2>");
+document.write("<scr" + "ipt>document.write('<p>before subtext</p><scri'+'pt>document.write(`third nest`)</scri'+'pt>')</scrip" + "t><p>fin</p>");
+</script>
+<p>Subtext.</p>
+</body>
+</html>
+
diff --git a/test/js/docwrite4.html b/test/js/docwrite4.html
new file mode 100644
index 00000000..0f0988b5
--- /dev/null
+++ b/test/js/docwrite4.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<title>document.write test</title>
+<script>
+window.onload = function() {
+	const success = document.body.innerHTML == document.querySelector("style").textContent;
+	while (document.body.childNodes[0])
+		document.body.childNodes[0].remove();
+	document.body.innerHTML = success ? "Success" : "Fail";
+}
+let checkpointCounter = 0;
+function checkpoint(n) {
+	if (++checkpointCounter != n)
+		throw new TypeError(`Checkpoint failed: expected ${n} but got ${checkpointCounter}`);
+}
+</script>
+<style><script>
+document.write(`<script>
+document.write("a");
+`);
+document.write(`
+document.write("<script></scr" + "ipt>x");
+`);
+document.write(`
+document.write("t");
+</scr` + "ipt>");
+</script><script>
+document.write("a");
+
+document.write("<script></scr" + "ipt>x");
+
+document.write("t");
+</script>a<script></script>xt
+
+</style>
+</head>
+<body><script>
+document.write(`<script>
+document.write("a");
+`);
+document.write(`
+document.write("<script></scr" + "ipt>x");
+`);
+document.write(`
+document.write("t");
+</scr` + "ipt>");
+</script></body>
+</html>
diff --git a/test/js/encode_decode.html b/test/js/encode_decode.html
new file mode 100644
index 00000000..069ddc72
--- /dev/null
+++ b/test/js/encode_decode.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<title>TextEncoder/TextDecoder test</title>
+<div id="success">Fail</div>
+<script>
+(function() {
+	/* Adapted from: https://developer.mozilla.org/en-US/docs/Glossary/Base64#the_unicode_problem */
+	function base64ToBytes(base64) {
+		const binString = atob(base64);
+		const result = [];
+		for (const c of binString)
+			result.push(Uint8Array.from(c, (m) => m.codePointAt(0)));
+		return result;
+	}
+
+	function bytesToBase64(bytes) {
+		const binString = String.fromCodePoint(...bytes);
+		return btoa(binString);
+	}
+
+	const utf8 = new TextEncoder().encode("a Ā 𐀀 文 🦄")
+	const b64utf8 = bytesToBase64(utf8);
+	if (b64utf8 !== "YSDEgCDwkICAIOaWhyDwn6aE") {
+		console.log(b64utf8);
+		return;
+	}
+	const dec = new TextDecoder();
+	const bytes = base64ToBytes(b64utf8);
+	const a = [];
+	let res = "";
+	for (const c of bytes)
+		res += dec.decode(c, {stream: true});
+	res += dec.decode();
+	if (res !== "a Ā 𐀀 文 🦄") {
+		console.log(res);
+		return;
+	}
+	document.getElementById("success").textContent = "Success";
+})();
+</script>
diff --git a/test/js/htmlcollection.html b/test/js/htmlcollection.html
new file mode 100644
index 00000000..6231237a
--- /dev/null
+++ b/test/js/htmlcollection.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<title>HTMLCollection test</title>
+<div class="abc">Fail</div>
+<style>style 1</style>
+<style>style 2</style>
+<style>style 3</style>
+<script>
+(function() {
+	const abc = document.getElementsByClassName("abc");
+	if (abc.length !== 1) return;
+	abc[0].className = "defg";
+	if (abc.length !== 0) return;
+	const styles = document.getElementsByTagName("style");
+	if (styles.length !== 3) return;
+	if (styles[0].textContent !== "style 1") return;
+	if (styles[1].textContent !== "style 2") return;
+	if (styles[2].textContent !== "style 3") return;
+	for (const style of styles) style.remove();
+	let defg = document.getElementsByClassName("defg");
+	defg[0].textContent = "Success";
+})()
+</script>
diff --git a/test/js/outerhtml.html b/test/js/outerhtml.html
new file mode 100644
index 00000000..5c30bc52
--- /dev/null
+++ b/test/js/outerhtml.html
@@ -0,0 +1,9 @@
+<!doctype html>
+<title>innerHTML test</title>
+<div id="test">Fail</div>
+<script>
+const div = document.getElementById("test");
+if (div.outerHTML != '<div id="test">Fail</div>')
+	throw new TypeError("invalid outerHTML " + div.outerHTML);
+div.textContent = "Success";
+</script>
diff --git a/test/js/prev_next_parent_child.html b/test/js/prev_next_parent_child.html
new file mode 100644
index 00000000..85abe7fe
--- /dev/null
+++ b/test/js/prev_next_parent_child.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<main>
+<div id=x>Fail</div>
+test
+<a id=y>test test</a>
+</main>
+<script>
+(function() {
+	let x = document.getElementById("x")
+	let y = document.getElementById("y");
+	if (y.previousSibling === x) return;
+	if (y.previousSibling.textContent.trim() !== "test") return;
+	if (y.previousElementSibling !== x) return;
+	if (x.nextElementSibling !== y) return;
+	if (x.nextSibling.textContent.trim() !== "test") return;
+	x.nextSibling.remove();
+	x.nextSibling.remove();
+	if (x.parentElement.children.length !== 1) return;
+	if (x.parentElement.children[0] !== x) return;
+	x.textContent = "Success";
+})()
+</script>
diff --git a/test/js/query_selector_plus.html b/test/js/query_selector_plus.html
new file mode 100644
index 00000000..0bbe1677
--- /dev/null
+++ b/test/js/query_selector_plus.html
@@ -0,0 +1,11 @@
+<!DOCTYPE HTML>
+<div id=success>Fail</div>
+<script one>
+</script>
+<script two>
+</script>
+<script>
+if (document.querySelector("script[one] + script").attributes["two"]) {
+	document.getElementById("success").textContent = "Success";
+}
+</script>
diff --git a/test/js/reflect.html b/test/js/reflect.html
new file mode 100644
index 00000000..45debe39
--- /dev/null
+++ b/test/js/reflect.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<div id=abc>Fail</div>
+<a class=claz target="abcd">test test</a>
+<script>
+(function() {
+	let x = document.getElementById("abc")
+	let a = document.getElementsByTagName("a")[0];
+	if (a.target != "abcd") return;
+	a.target = "defg";
+	if (a.target != "defg") return;
+	if (a.relList != "") return;
+	a.relList = "...";
+	if (a.relList != "...") return;
+	if (a.className != "claz") return;
+	x.textContent = "Success";
+	a.remove(); /* ignore target... */
+})()
+</script>
diff --git a/test/js/run_js_tests.sh b/test/js/run_js_tests.sh
new file mode 100755
index 00000000..a8cad435
--- /dev/null
+++ b/test/js/run_js_tests.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+if ! test "$CHA_TEST_BIN"
+then	test -f ../../../cha && CHA_TEST_BIN=../../../cha || CHA_TEST_BIN=cha
+fi
+failed=0
+for h in *.html
+do	printf '%s\n' "$h"
+	if ! "$CHA_TEST_BIN" -C config.toml "$h" | diff all.expected -
+	then	failed=$(($failed+1))
+		printf 'FAIL: %s\n' "$h"
+	fi
+done
+exit "$failed"
diff --git a/test/js/settimeout.html b/test/js/settimeout.html
new file mode 100644
index 00000000..e57dba7f
--- /dev/null
+++ b/test/js/settimeout.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<title>setTimeout test</title>
+<!-- For now, this only tests whether setTimeout crashes the buffer
+     or not.  (There has been a bug where it did.) -->
+<script>
+setTimeout(() => void(0), 1000);
+</script>
+Success
diff --git a/test/js/template.html b/test/js/template.html
new file mode 100644
index 00000000..33bbdc34
--- /dev/null
+++ b/test/js/template.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<title>Test template</title>
+<div id=x>Fail</div>
+<script src=asserts.js></script>
+<script>
+assert(true);
+document.getElementById("x").textContent = "Success";
+</script>
diff --git a/test/js/text.html b/test/js/text.html
new file mode 100644
index 00000000..7d7bcfca
--- /dev/null
+++ b/test/js/text.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<div id="succ">Fail</div>
+<script>
+(function() {
+	if (new Text("data").ownerDocument != document) return;
+	document.getElementById("succ").textContent = "Success"
+})()
+</script>
diff --git a/test/js/window.html b/test/js/window.html
new file mode 100644
index 00000000..5aef5186
--- /dev/null
+++ b/test/js/window.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<title>Window test</title>
+<div id=x>Fail</div>
+<script src=asserts.js></script>
+<script>
+assert_equals(window.toString(), "[object Window]");
+const desc = Object.getOwnPropertyDescriptor(window, "window");
+assert(desc.enumerable, "window must be enumerable");
+assert(!desc.configurable, "window must not be configurable");
+document.getElementById("x").textContent = "Success";
+</script>