aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.eslintrc.json16
-rw-r--r--test/data/html/document-util.html (renamed from test/data/html/test-document1.html)105
-rw-r--r--test/data/html/dom-text-scanner.html (renamed from test/data/html/test-dom-text-scanner.html)156
-rw-r--r--test/data/html/js/html-test-utilities.js184
-rw-r--r--test/data/html/js/performance-frames.js63
-rw-r--r--test/data/html/js/popup-tests-frame1.js21
-rw-r--r--test/data/html/js/popup-tests.js33
-rw-r--r--test/data/html/performance-frame1.html26
-rw-r--r--test/data/html/performance-frame2.html33
-rw-r--r--test/data/html/performance.html27
-rw-r--r--test/data/html/popup-tests-frame1.html (renamed from test/data/html/test-document2-frame1.html)18
-rw-r--r--test/data/html/popup-tests-frame2.svg (renamed from test/data/html/test-document2-frame2.svg)0
-rw-r--r--test/data/html/popup-tests.html (renamed from test/data/html/test-document2.html)228
-rw-r--r--test/data/html/test-document2-script.js121
-rw-r--r--test/data/html/test-document3-frame1.html44
-rw-r--r--test/data/html/test-document3-frame2.html62
-rw-r--r--test/data/html/test-document3.html26
-rw-r--r--test/data/html/test-stylesheet.css12
-rw-r--r--test/document-util.test.js2
-rw-r--r--test/dom-text-scanner.test.js4
-rw-r--r--test/playwright/visual.spec.js16
21 files changed, 638 insertions, 559 deletions
diff --git a/.eslintrc.json b/.eslintrc.json
index a93888bb..1a427686 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -661,7 +661,7 @@
},
{
"files": [
- "test/data/html/*.js"
+ "test/data/html/**/*.js"
],
"parserOptions": {
"sourceType": "script"
@@ -670,9 +670,17 @@
"browser": true,
"node": false,
"webextensions": false
- },
- "rules": {
- "no-implicit-globals": "off"
+ }
+ },
+ {
+ "files": [
+ "test/data/html/**/*.js"
+ ],
+ "excludedFiles": [
+ "test/data/html/js/html-test-utilities.js"
+ ],
+ "globals": {
+ "HtmlTestUtilities": "readonly"
}
},
{
diff --git a/test/data/html/test-document1.html b/test/data/html/document-util.html
index d66e459d..d8ac012e 100644
--- a/test/data/html/test-document1.html
+++ b/test/data/html/document-util.html
@@ -1,18 +1,19 @@
<!DOCTYPE html>
<html>
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width,initial-scale=1">
- <title>Yomitan Tests</title>
- <link rel="icon" type="image/gif" href="data:image/gif;base64,R0lGODlhEAAQAKEBAAAAAP///////////yH5BAEKAAIALAAAAAAQABAAAAImFI6Zpt0B4YkS0TCpq07xbmEgcGVRUpLaI46ZG7ppalY0jDCwUAAAOw==">
- <link rel="stylesheet" href="test-stylesheet.css">
- </head>
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width,initial-scale=1">
+ <title>DocumentUtil Tests</title>
+ <link rel="icon" type="image/gif" href="data:image/gif;base64,R0lGODdhAQABAIABAAAAAP///ywAAAAAAQABAAACAkQBADs=">
+ <link rel="stylesheet" href="test-stylesheet.css">
+</head>
<body>
- <h1>Yomitan Tests</h1>
+ <h1>DocumentUtil Tests</h1>
- <div
- class="test"
+ <test-description>Automated test cases for DocumentUtil.</test-description>
+
+ <test-case
data-test-type="scan"
data-element-from-point-selector="span"
data-caret-range-from-point-selector="span"
@@ -25,10 +26,9 @@
data-sentence="真白「心配してくださって、ありがとございます」"
>
<span>真白「心配してくださって、ありがとございます」</span>
- </div>
+ </test-case>
- <div
- class="test"
+ <test-case
data-test-type="scan"
data-element-from-point-selector="span"
data-caret-range-from-point-selector="span"
@@ -41,10 +41,9 @@
data-sentence="心配してくださって、ありがとございます"
>
<span>真白「心配してくださって、ありがとございます」</span>
- </div>
+ </test-case>
- <div
- class="test"
+ <test-case
data-test-type="scan"
data-element-from-point-selector="span"
data-caret-range-from-point-selector="span"
@@ -57,10 +56,9 @@
data-sentence="心配して「くださって」、ありがと「ございます」"
>
<span>真白「心配して「くださって」、ありがと「ございます」」</span>
- </div>
+ </test-case>
- <div
- class="test"
+ <test-case
data-test-type="scan"
data-element-from-point-selector="span"
data-caret-range-from-point-selector="span"
@@ -73,10 +71,9 @@
data-sentence="ありがとございます。"
>
<span>ありがとございます。ありがとございます。</span>
- </div>
+ </test-case>
- <div
- class="test"
+ <test-case
data-test-type="scan"
data-element-from-point-selector="span"
data-caret-range-from-point-selector="span"
@@ -89,10 +86,9 @@
data-sentence="ありがとございます。"
>
<span>ありがとございます。ありがとございます。</span>
- </div>
+ </test-case>
- <div
- class="test"
+ <test-case
data-test-type="scan"
data-element-from-point-selector="span"
data-caret-range-from-point-selector="span"
@@ -105,10 +101,9 @@
data-sentence="ありがとございます。!?"
>
<span>ありがとございます。!?ありがとございます。!?</span>
- </div>
+ </test-case>
- <div
- class="test"
+ <test-case
data-test-type="scan"
data-element-from-point-selector="span"
data-caret-range-from-point-selector="span"
@@ -121,10 +116,9 @@
data-sentence="ありがとございます!!!"
>
<span>ありがとございます!!!ありがとございます!!!</span>
- </div>
+ </test-case>
- <div
- class="test"
+ <test-case
data-test-type="scan"
data-element-from-point-selector="input"
data-caret-range-from-point-selector="input"
@@ -138,10 +132,9 @@
data-has-imposter="true"
>
<input type="text" value="真白「心配してくださって、ありがとございます」" style="width: 100%; box-sizing: border-box; font-family: inherit; font-size: inherit; border: 1px solid #d8d8d8; padding: 0.2em;">
- </div>
+ </test-case>
- <div
- class="test"
+ <test-case
data-test-type="scan"
data-element-from-point-selector="textarea"
data-caret-range-from-point-selector="textarea"
@@ -155,10 +148,9 @@
data-has-imposter="true"
>
<textarea style="width: 100%; height: 3em; box-sizing: border-box; font-family: inherit; font-size: inherit; border: 1px solid #d8d8d8; padding: 0.2em;">真白「心配してくださって、ありがとございます」</textarea>
- </div>
+ </test-case>
- <div
- class="test"
+ <test-case
data-test-type="scan"
data-element-from-point-selector="button"
data-caret-range-from-point-selector="button"
@@ -171,10 +163,9 @@
data-sentence="よみたん"
>
<button type="button" style="width: 100%; box-sizing: border-box; font-family: inherit; font-size: inherit; border: 1px solid #d8d8d8; background-color: #f0f0f0; padding: 0.2em;">よみたん</button>
- </div>
+ </test-case>
- <div
- class="test"
+ <test-case
data-test-type="scan"
data-element-from-point-selector="img"
data-caret-range-from-point-selector="img"
@@ -186,11 +177,10 @@
data-sentence-scan-extent="100"
data-sentence="よみたん"
>
- <img src="data:image/gif;base64,R0lGODdhBwAHAIABAAAAAP///ywAAAAABwAHAAACDIRvEaC32FpCbEkKCgA7" alt="よみたん" title="よみたん" style="width: 70px; height: 70px; image-rendering: crisp-edges; image-rendering: pixelated; display: block;">
- </div>
+ <img src="data:image/gif;base64,R0lGODdhAQABAIABAAAAAP///ywAAAAAAQABAAACAkQBADs=" alt="よみたん" title="よみたん" style="width: 70px; height: 70px; image-rendering: crisp-edges; image-rendering: pixelated; display: block;">
+ </test-case>
- <div
- class="test"
+ <test-case
data-test-type="scan"
data-element-from-point-selector="span:nth-of-type(3)"
data-caret-range-from-point-selector="span:nth-of-type(3)"
@@ -208,10 +198,9 @@
<span>ありがとございます3</span>
<span>ありがとございます4</span>
<span>ありがとございます5</span>
- </div>
+ </test-case>
- <div
- class="test"
+ <test-case
data-test-type="scan"
data-element-from-point-selector="span:nth-of-type(3)"
data-caret-range-from-point-selector="span:nth-of-type(3)"
@@ -229,10 +218,9 @@
<span>ありがとございます3</span>
<span>ありがとございます4</span>
<span>ありがとございます5</span>
- </div>
+ </test-case>
- <div
- class="test"
+ <test-case
data-test-type="text-source-range-seek"
data-seek-node-selector="span:nth-of-type(1)"
data-seek-node-is-text="true"
@@ -267,10 +255,9 @@
らりるれろ
わゐ&#x3000;ゑを
</span><span>trailing content</span>
- </div>
+ </test-case>
- <div
- class="test"
+ <test-case
data-test-type="text-source-range-seek"
data-seek-node-selector="span:nth-of-type(1)"
data-seek-node-is-text="true"
@@ -305,10 +292,9 @@
らりるれろ
わゐ&#x3000;ゑを
</span><span>trailing content</span>
- </div>
+ </test-case>
- <div
- class="test"
+ <test-case
data-test-type="text-source-range-seek"
data-seek-node-selector="span:nth-of-type(1)"
data-seek-node-is-text="true"
@@ -343,10 +329,9 @@
らりるれろ
わゐ&#x3000;ゑを
</span><span>trailing content</span>
- </div>
+ </test-case>
- <div
- class="test"
+ <test-case
data-test-type="text-source-range-seek"
data-seek-node-selector="span:nth-of-type(2)"
data-seek-node-is-text="true"
@@ -381,7 +366,7 @@
らりるれろ
わゐ&#x3000;ゑを
</span><span>trailing content</span>
- </div>
+ </test-case>
</body>
</html>
diff --git a/test/data/html/test-dom-text-scanner.html b/test/data/html/dom-text-scanner.html
index f22e0895..ff4d0493 100644
--- a/test/data/html/test-dom-text-scanner.html
+++ b/test/data/html/dom-text-scanner.html
@@ -1,17 +1,19 @@
<!DOCTYPE html>
<html>
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width,initial-scale=1">
- <title>Yomitan DOMTextScanner Tests</title>
- <link rel="icon" type="image/gif" href="data:image/gif;base64,R0lGODlhEAAQAKEBAAAAAP///////////yH5BAEKAAIALAAAAAAQABAAAAImFI6Zpt0B4YkS0TCpq07xbmEgcGVRUpLaI46ZG7ppalY0jDCwUAAAOw==">
- <link rel="stylesheet" href="test-stylesheet.css">
- </head>
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width,initial-scale=1">
+ <title>DOMTextScanner Tests</title>
+ <link rel="icon" type="image/gif" href="data:image/gif;base64,R0lGODdhAQABAIABAAAAAP///ywAAAAAAQABAAACAkQBADs=">
+ <link rel="stylesheet" href="test-stylesheet.css">
+</head>
<body>
- <h1>Yomitan DOMTextScanner Tests</h1>
+ <h1>DOMTextScanner Tests</h1>
- <y-test
+ <test-description>Automated test cases for DOMTextScanner.</test-description>
+
+ <test-case
data-test-data='{
"node": "div:nth-of-type(1)",
"offset": 0,
@@ -23,12 +25,12 @@
}
}'
>
- <y-description>Layout newlines expected due to entering and exiting display:block nodes.</y-description>
+ <test-description>Layout newlines expected due to entering and exiting display:block nodes.</test-description>
<div><div>小ぢん</div>まり1</div>
<div>小ぢん<div>まり2</div></div>
- </y-test>
+ </test-case>
- <y-test
+ <test-case
data-test-data='{
"node": "div:nth-of-type(1)::text",
"offset": 0,
@@ -40,11 +42,11 @@
}
}'
>
- <y-description>Layout newline expected due to sequential display:block elements.</y-description>
+ <test-description>Layout newline expected due to sequential display:block elements.</test-description>
<div>小ぢんまり1</div><div>小ぢんまり2</div>
- </y-test>
+ </test-case>
- <y-test
+ <test-case
data-test-data='{
"node": "div:nth-of-type(1)::text",
"offset": 0,
@@ -56,12 +58,12 @@
}
}'
>
- <y-description>Layout newline expected due to sequential display:block elements separated by a newline.</y-description>
+ <test-description>Layout newline expected due to sequential display:block elements separated by a newline.</test-description>
<div>小ぢんまり1</div>
<div>小ぢんまり2</div>
- </y-test>
+ </test-case>
- <y-test
+ <test-case
data-test-data='{
"node": "span:nth-of-type(1)::text",
"offset": 0,
@@ -73,11 +75,11 @@
}
}'
>
- <y-description>No newlines expected due to display:inline.</y-description>
+ <test-description>No newlines expected due to display:inline.</test-description>
<span>小ぢんまり1</span><span>小ぢんまり2</span>
- </y-test>
+ </test-case>
- <y-test
+ <test-case
data-test-data='{
"node": "span:nth-of-type(1)::text",
"offset": 0,
@@ -89,12 +91,12 @@
}
}'
>
- <y-description>No newlines expected due to white-space:normal.</y-description>
+ <test-description>No newlines expected due to white-space:normal.</test-description>
<span>小ぢんまり1</span>
<span>小ぢんまり2</span>
- </y-test>
+ </test-case>
- <y-test
+ <test-case
data-test-data='{
"node": "span:nth-of-type(1)::text",
"offset": 0,
@@ -106,14 +108,14 @@
}
}'
>
- <y-description>Newline expected due to white-space:pre.</y-description>
+ <test-description>Newline expected due to white-space:pre.</test-description>
<pre>
<span>小ぢんまり1</span>
<span>小ぢんまり2</span>
</pre>
- </y-test>
+ </test-case>
- <y-test
+ <test-case
data-test-data='{
"node": "span:nth-of-type(1)::text",
"offset": 0,
@@ -125,11 +127,11 @@
}
}'
>
- <y-description>No newlines expected due to display:inline-block. Actual layout flow cannot be determined by DOM/CSS alone.</y-description>
+ <test-description>No newlines expected due to display:inline-block. Actual layout flow cannot be determined by DOM/CSS alone.</test-description>
<span style="display: inline-block;">小ぢんまり1</span><span style="display: inline-block;">小ぢんまり2</span>
- </y-test>
+ </test-case>
- <y-test
+ <test-case
style="position: relative;"
data-test-data='{
"node": "div:nth-of-type(1)::text",
@@ -142,11 +144,11 @@
}
}'
>
- <y-description>Single newline expected due to display:block layout.</y-description>
+ <test-description>Single newline expected due to display:block layout.</test-description>
<div>小ぢんまり1</div><div style="position: relative;">小ぢんまり2</div>
- </y-test>
+ </test-case>
- <y-test
+ <test-case
style="position: relative; overflow: hidden;"
data-test-data='{
"node": "div:nth-of-type(1)::text",
@@ -159,11 +161,11 @@
}
}'
>
- <y-description>Two newlines expected due to position:absolute causing a significant layout change.</y-description>
+ <test-description>Two newlines expected due to position:absolute causing a significant layout change.</test-description>
<div>小ぢんまり1</div><div style="position: absolute;">小ぢんまり2</div>
- </y-test>
+ </test-case>
- <y-test
+ <test-case
style="position: relative; overflow: hidden;"
data-test-data='{
"node": "div:nth-of-type(1)::text",
@@ -176,11 +178,11 @@
}
}'
>
- <y-description>Two newlines expected due to position:fixed causing a significant layout change.</y-description>
+ <test-description>Two newlines expected due to position:fixed causing a significant layout change.</test-description>
<div>小ぢんまり1</div><div style="position: fixed;">小ぢんまり2</div>
- </y-test>
+ </test-case>
- <y-test
+ <test-case
style="position: relative;"
data-test-data='{
"node": "div:nth-of-type(1)::text",
@@ -193,11 +195,11 @@
}
}'
>
- <y-description>Two newlines expected due to position:sticky being able to cause a significant layout change.</y-description>
+ <test-description>Two newlines expected due to position:sticky being able to cause a significant layout change.</test-description>
<div>小ぢんまり1</div><div style="position: sticky;">小ぢんまり2</div>
- </y-test>
+ </test-case>
- <y-test
+ <test-case
data-test-data='{
"node": "rt",
"offset": 0,
@@ -209,11 +211,11 @@
}
}'
>
- <y-description>Scanning text starting in an &lt;rt&gt; element. Should start scanning at the start of the &lt;ruby&gt; tag instead.</y-description>
+ <test-description>Scanning text starting in an &lt;rt&gt; element. Should start scanning at the start of the &lt;ruby&gt; tag instead.</test-description>
<div><ruby>小<rp>(</rp><rt>こ</rt><rp>)</rp></ruby>ぢんまり1</div>
- </y-test>
+ </test-case>
- <y-test
+ <test-case
data-test-data='{
"node": "div",
"offset": 0,
@@ -225,11 +227,11 @@
}
}'
>
- <y-description>Skip &lt;script&gt; content.</y-description>
+ <test-description>Skip &lt;script&gt; content.</test-description>
<div>小ぢん<script>/*comment*/</script>まり1</div>
- </y-test>
+ </test-case>
- <y-test
+ <test-case
data-test-data='{
"node": "div",
"offset": 0,
@@ -241,11 +243,11 @@
}
}'
>
- <y-description>Skip &lt;style&gt; content.</y-description>
+ <test-description>Skip &lt;style&gt; content.</test-description>
<div>小ぢん<style>/*comment*/</style>まり1</div>
- </y-test>
+ </test-case>
- <y-test
+ <test-case
data-test-data='{
"node": "div",
"offset": 0,
@@ -257,11 +259,11 @@
}
}'
>
- <y-description>Skip &lt;textarea&gt; content.</y-description>
+ <test-description>Skip &lt;textarea&gt; content.</test-description>
<div>小ぢん<textarea>textarea content</textarea>まり1</div>
- </y-test>
+ </test-case>
- <y-test
+ <test-case
data-test-data='{
"node": "div",
"offset": 0,
@@ -273,11 +275,11 @@
}
}'
>
- <y-description>Skip &lt;input&gt; content.</y-description>
+ <test-description>Skip &lt;input&gt; content.</test-description>
<div>小ぢん<input value="content">まり1</div>
- </y-test>
+ </test-case>
- <y-test
+ <test-case
data-test-data='{
"node": "div",
"offset": 0,
@@ -289,11 +291,11 @@
}
}'
>
- <y-description>Skip &lt;button&gt; content.</y-description>
+ <test-description>Skip &lt;button&gt; content.</test-description>
<div>小ぢん<button type="button">content</button>まり1</div>
- </y-test>
+ </test-case>
- <y-test
+ <test-case
data-test-data='{
"node": "div",
"offset": 0,
@@ -305,11 +307,11 @@
}
}'
>
- <y-description>Skip content with font-size:0.</y-description>
+ <test-description>Skip content with font-size:0.</test-description>
<div>小ぢん<span style="font-size: 0;">content</span>まり1</div>
- </y-test>
+ </test-case>
- <y-test
+ <test-case
data-test-data='{
"node": "div",
"offset": 0,
@@ -321,11 +323,11 @@
}
}'
>
- <y-description>Skip content with opacity:0.</y-description>
+ <test-description>Skip content with opacity:0.</test-description>
<div>小ぢん<span style="opacity: 0;">content</span>まり1</div>
- </y-test>
+ </test-case>
- <y-test
+ <test-case
data-test-data='{
"node": "div",
"offset": 0,
@@ -337,11 +339,11 @@
}
}'
>
- <y-description>Skip content with visibility:hidden.</y-description>
+ <test-description>Skip content with visibility:hidden.</test-description>
<div>小ぢん<span style="visibility: hidden;">content</span>まり1</div>
- </y-test>
+ </test-case>
- <y-test
+ <test-case
data-test-data='{
"node": "div",
"offset": 0,
@@ -353,11 +355,11 @@
}
}'
>
- <y-description>Skip content with display:none.</y-description>
+ <test-description>Skip content with display:none.</test-description>
<div>小ぢん<span style="display: none;">content</span>まり1</div>
- </y-test>
+ </test-case>
- <y-test
+ <test-case
data-test-data='{
"node": "div",
"offset": 0,
@@ -369,11 +371,11 @@
}
}'
>
- <y-description>Don't skip content with user-select:none.</y-description>
+ <test-description>Don't skip content with user-select:none.</test-description>
<div>小ぢ<span style="user-select: none;">ん</span>まり1</div>
- </y-test>
+ </test-case>
- <y-test
+ <test-case
data-test-data='{
"node": "div",
"offset": 0,
@@ -385,9 +387,9 @@
}
}'
>
- <y-description>Skip content with user-select:none <em>and</em> a transparent color.</y-description>
+ <test-description>Skip content with user-select:none <em>and</em> a transparent color.</test-description>
<div>小ぢん<span style="user-select: none; color: rgba(0, 0, 0, 0);">content</span>まり1</div>
- </y-test>
+ </test-case>
</body>
</html> \ No newline at end of file
diff --git a/test/data/html/js/html-test-utilities.js b/test/data/html/js/html-test-utilities.js
new file mode 100644
index 00000000..da3e753a
--- /dev/null
+++ b/test/data/html/js/html-test-utilities.js
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2023 Yomitan Authors
+ * Copyright (C) 2021-2022 Yomichan Authors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+class HtmlTestUtilities {
+ /**
+ * @param {Element} element
+ */
+ static requestFullscreen(element) {
+ if (element.requestFullscreen) {
+ element.requestFullscreen();
+ // @ts-expect-error - Browser compatibility
+ } else if (element.mozRequestFullScreen) {
+ // @ts-expect-error - Browser compatibility
+ element.mozRequestFullScreen();
+ // @ts-expect-error - Browser compatibility
+ } else if (element.webkitRequestFullscreen) {
+ // @ts-expect-error - Browser compatibility
+ element.webkitRequestFullscreen();
+ // @ts-expect-error - Browser compatibility
+ } else if (element.msRequestFullscreen) {
+ // @ts-expect-error - Browser compatibility
+ element.msRequestFullscreen();
+ }
+ }
+
+ /** */
+ static exitFullscreen() {
+ if (document.exitFullscreen) {
+ document.exitFullscreen();
+ // @ts-expect-error - Browser compatibility
+ } else if (document.mozCancelFullScreen) {
+ // @ts-expect-error - Browser compatibility
+ document.mozCancelFullScreen();
+ // @ts-expect-error - Browser compatibility
+ } else if (document.webkitExitFullscreen) {
+ // @ts-expect-error - Browser compatibility
+ document.webkitExitFullscreen();
+ // @ts-expect-error - Browser compatibility
+ } else if (document.msExitFullscreen) {
+ // @ts-expect-error - Browser compatibility
+ document.msExitFullscreen();
+ }
+ }
+
+ /**
+ * @returns {?Element}
+ */
+ static getFullscreenElement() {
+ return (
+ document.fullscreenElement ||
+ // @ts-expect-error - Browser compatibility
+ document.msFullscreenElement ||
+ // @ts-expect-error - Browser compatibility
+ document.mozFullScreenElement ||
+ // @ts-expect-error - Browser compatibility
+ document.webkitFullscreenElement ||
+ null
+ );
+ }
+
+ /**
+ * @param {Element} element
+ */
+ static toggleFullscreen(element) {
+ if (this.getFullscreenElement()) {
+ this.exitFullscreen();
+ } else {
+ this.requestFullscreen(element);
+ }
+ }
+
+ /**
+ * @param {string} string
+ * @returns {Uint8Array}
+ */
+ static stringToTypedArray(string) {
+ const array = new Uint8Array(string.length);
+ for (let i = 0; i < string.length; ++i) {
+ array[i] = string.charCodeAt(i);
+ }
+ return array;
+ }
+
+ /**
+ * @param {string} dataUrl
+ * @returns {{content: string, type: string}}
+ * @throws {Error}
+ */
+ static dataUrlToContent(dataUrl) {
+ const match = /^data:([^;]*);(base64,)?([\w\W]*)$/.exec(dataUrl);
+ if (match === null) { throw new Error('Invalid input'); }
+ const [, type, isBase64, data] = match;
+ const content = (
+ isBase64 ?
+ new TextDecoder().decode(this.stringToTypedArray(atob(data))) :
+ data
+ );
+ return {content, type};
+ }
+
+ /**
+ * @param {string} dataUrl
+ * @returns {Blob}
+ */
+ static dataUrlToBlob(dataUrl) {
+ const {content, type} = this.dataUrlToContent(dataUrl);
+ return new Blob([content], {type});
+ }
+
+ /**
+ * @param {?Element} element
+ * @returns {string}
+ * @throws {Error}
+ */
+ static getIframeSrc(element) {
+ if (!(element instanceof HTMLIFrameElement)) {
+ throw new Error('Element is not an iframe');
+ }
+ return element.src;
+ }
+
+ /**
+ * @param {Element|DocumentFragment} container
+ * @param {?Element} [fullscreenElement]
+ */
+ static setupTest(container, fullscreenElement = null) {
+ const fullscreenLink = container.querySelector('.fullscreen-link');
+ if (fullscreenLink !== null) {
+ if (fullscreenElement === null) {
+ fullscreenElement = container.querySelector('.fullscreen-element');
+ }
+ fullscreenLink.addEventListener('click', (e) => {
+ if (fullscreenElement === null) { return; }
+ this.toggleFullscreen(fullscreenElement);
+ e.preventDefault();
+ return false;
+ }, false);
+ }
+
+ const template = container.querySelector('template');
+ const templateContentContainer = container.querySelector('.template-content-container');
+ if (template !== null && templateContentContainer !== null) {
+ const mode = (container instanceof HTMLElement ? container.dataset.shadowMode : void 0);
+ const shadow = templateContentContainer.attachShadow({
+ mode: (mode === 'open' || mode === 'closed' ? mode : 'open')
+ });
+
+ const containerStyles = document.querySelector('#container-styles');
+ if (containerStyles !== null) {
+ shadow.appendChild(containerStyles.cloneNode(true));
+ }
+
+ const content = document.importNode(template.content, true);
+ this.setupTest(content);
+ shadow.appendChild(content);
+ }
+ }
+
+ /**
+ * @param {() => void} main
+ */
+ static runMain(main) {
+ if (document.readyState === 'loading') {
+ document.addEventListener('DOMContentLoaded', () => { main(); });
+ } else {
+ main();
+ }
+ }
+}
diff --git a/test/data/html/js/performance-frames.js b/test/data/html/js/performance-frames.js
new file mode 100644
index 00000000..7484f971
--- /dev/null
+++ b/test/data/html/js/performance-frames.js
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2023 Yomitan Authors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+HtmlTestUtilities.runMain(() => {
+ let totalCount = 0;
+ const container = document.querySelector('#container');
+ const counter = document.querySelector('#counter');
+
+ /**
+ * @param {number} count
+ * @param {Event} event
+ */
+ function addElements(count, event) {
+ event.preventDefault();
+
+ if (container !== null) {
+ for (let i = 0; i < count; ++i) {
+ const element = document.createElement('div');
+ element.textContent = 'ありがとう';
+ container.appendChild(element);
+ }
+ }
+
+ totalCount += count;
+ if (counter !== null) {
+ counter.textContent = `${totalCount}`;
+ }
+ }
+
+ for (const element of document.querySelectorAll('.add-elements')) {
+ if (!(element instanceof HTMLElement)) { continue; }
+ const {count} = element.dataset;
+ if (typeof count !== 'string') { continue; }
+ const countValue = Number.parseInt(count, 10);
+ if (!Number.isFinite(countValue)) { continue; }
+ element.addEventListener('click', addElements.bind(null, countValue));
+ }
+
+ const shadowIframeContainer = document.querySelector('#shadow-iframe-container-open');
+ if (shadowIframeContainer !== null) {
+ const shadow = shadowIframeContainer.attachShadow({mode: 'open'});
+ const templateElement = document.querySelector('#shadow-iframe-container-open-content-template');
+ if (templateElement instanceof HTMLTemplateElement) {
+ const template = templateElement.content;
+ const content = document.importNode(template, true);
+ shadow.appendChild(content);
+ }
+ }
+});
diff --git a/test/data/html/js/popup-tests-frame1.js b/test/data/html/js/popup-tests-frame1.js
new file mode 100644
index 00000000..b1dc2756
--- /dev/null
+++ b/test/data/html/js/popup-tests-frame1.js
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2023 Yomitan Authors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+HtmlTestUtilities.runMain(() => {
+ const {body} = document;
+ HtmlTestUtilities.setupTest(body, body);
+});
diff --git a/test/data/html/js/popup-tests.js b/test/data/html/js/popup-tests.js
new file mode 100644
index 00000000..3a46a045
--- /dev/null
+++ b/test/data/html/js/popup-tests.js
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2023 Yomitan Authors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+HtmlTestUtilities.runMain(() => {
+ for (const element of document.querySelectorAll('test-case')) {
+ HtmlTestUtilities.setupTest(element);
+ }
+
+ const iframeWithDataUrl = document.querySelector('#iframe-with-data-url');
+ const src = HtmlTestUtilities.getIframeSrc(iframeWithDataUrl);
+ const iframeWithBlobUrl = document.querySelector('#iframe-with-blob-url');
+ if (iframeWithBlobUrl instanceof HTMLIFrameElement) {
+ iframeWithBlobUrl.src = URL.createObjectURL(HtmlTestUtilities.dataUrlToBlob(src));
+ }
+ for (const iframeWithSrcdoc of document.querySelectorAll('.iframe-with-srcdoc')) {
+ if (!(iframeWithSrcdoc instanceof HTMLIFrameElement)) { continue; }
+ iframeWithSrcdoc.srcdoc = HtmlTestUtilities.dataUrlToContent(src).content;
+ }
+});
diff --git a/test/data/html/performance-frame1.html b/test/data/html/performance-frame1.html
new file mode 100644
index 00000000..a60ba241
--- /dev/null
+++ b/test/data/html/performance-frame1.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width,initial-scale=1">
+ <title>Performance Tests</title>
+ <link rel="stylesheet" href="test-stylesheet.css">
+ <script src="js/html-test-utilities.js"></script>
+ <script src="js/performance-frames.js"></script>
+</head>
+<body><div class="content">
+
+ <test-description>Add elements</test-description>
+
+ <div>
+ <a href="#" class="add-elements" data-count="1000">1000</a>
+ <a href="#" class="add-elements" data-count="10000">10000</a>
+ <a href="#" class="add-elements" data-count="100000">100000</a>
+ <a href="#" class="add-elements" data-count="1000000">1000000</a>
+ </div>
+
+ <div id="counter"></div>
+ <div id="container"></div>
+
+</div></body>
+</html>
diff --git a/test/data/html/performance-frame2.html b/test/data/html/performance-frame2.html
new file mode 100644
index 00000000..eb7d758b
--- /dev/null
+++ b/test/data/html/performance-frame2.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width,initial-scale=1">
+ <title>Performance Tests</title>
+ <link rel="stylesheet" href="test-stylesheet.css">
+ <script src="js/html-test-utilities.js"></script>
+ <script src="js/performance-frames.js"></script>
+</head>
+<body><div class="content">
+
+ <test-description>&lt;iframe&gt; element inside of an open shadow DOM.</test-description>
+
+ <div id="shadow-iframe-container-open"></div>
+ <template id="shadow-iframe-container-open-content-template">
+ <iframe src="popup-tests-frame1.html" allowfullscreen="true" style="width: 100%; height: 50px; border: 1px solid #d8d8d8;"></iframe>
+ </template>
+
+ <test-description>Add elements</test-description>
+
+ <div>
+ <a href="#" class="add-elements" data-count="1000">1000</a>
+ <a href="#" class="add-elements" data-count="10000">10000</a>
+ <a href="#" class="add-elements" data-count="100000">100000</a>
+ <a href="#" class="add-elements" data-count="1000000">1000000</a>
+ </div>
+
+ <div id="counter"></div>
+ <div id="container"></div>
+
+</div></body>
+</html>
diff --git a/test/data/html/performance.html b/test/data/html/performance.html
new file mode 100644
index 00000000..16a160e7
--- /dev/null
+++ b/test/data/html/performance.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width,initial-scale=1">
+ <title>Performance Tests</title>
+ <link rel="icon" type="image/gif" href="data:image/gif;base64,R0lGODdhAQABAIABAAAAAP///ywAAAAAAQABAAACAkQBADs=">
+ <link rel="stylesheet" href="test-stylesheet.css">
+</head>
+<body>
+
+ <h1>Performance Tests</h1>
+
+ <test-description>Testing performance with artificially demanding cases in a real browser</test-description>
+
+ <test-case>
+ <test-description>&lt;iframe&gt; element.</test-description>
+ <iframe src="performance-frame1.html" allowfullscreen="true" style="width: 100%; height: 200px; border: 1px solid #d8d8d8;"></iframe>
+ </test-case>
+
+ <test-case>
+ <test-description>&lt;iframe&gt; element containing an &lt;iframe&gt; element inside of an open shadow DOM.</test-description>
+ <iframe src="performance-frame2.html" allowfullscreen="true" style="width: 100%; height: 200px; border: 1px solid #d8d8d8;"></iframe>
+ </test-case>
+
+</body>
+</html>
diff --git a/test/data/html/test-document2-frame1.html b/test/data/html/popup-tests-frame1.html
index 52243e1e..5074aac9 100644
--- a/test/data/html/test-document2-frame1.html
+++ b/test/data/html/popup-tests-frame1.html
@@ -1,11 +1,12 @@
<!DOCTYPE html>
<html>
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width,initial-scale=1">
- <title>Yomitan Tests</title>
- <script src="test-document2-script.js"></script>
- <style>
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width,initial-scale=1">
+ <title>Frame 1</title>
+ <script src="js/html-test-utilities.js"></script>
+ <script src="js/popup-tests-frame1.js"></script>
+ <style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px;
@@ -26,15 +27,14 @@ a, a:visited {
padding: 0.5em;
background-color: #f8f8f8;
}
- </style>
- </head>
+ </style>
+</head>
<body><div class="content">
<div>
ありがとう
</div>
<div>
<a href="#" class="fullscreen-link">Toggle fullscreen</a>
- <script>setup(document.body, document.body);</script>
</div>
</div></body>
</html> \ No newline at end of file
diff --git a/test/data/html/test-document2-frame2.svg b/test/data/html/popup-tests-frame2.svg
index 380eab97..380eab97 100644
--- a/test/data/html/test-document2-frame2.svg
+++ b/test/data/html/popup-tests-frame2.svg
diff --git a/test/data/html/test-document2.html b/test/data/html/popup-tests.html
index c822c1d0..ef2d36e6 100644
--- a/test/data/html/test-document2.html
+++ b/test/data/html/popup-tests.html
@@ -1,47 +1,46 @@
<!DOCTYPE html>
<html>
-
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
- <title>Yomitan Manual Tests</title>
- <link rel="icon" type="image/gif"
- href="data:image/gif;base64,R0lGODlhEAAQAKEBAAAAAP///////////yH5BAEKAAIALAAAAAAQABAAAAImFI6Zpt0B4YkS0TCpq07xbmEgcGVRUpLaI46ZG7ppalY0jDCwUAAAOw==">
+ <title>Popup Tests</title>
+ <link rel="icon" type="image/gif" href="data:image/gif;base64,R0lGODdhAQABAIABAAAAAP///ywAAAAAAQABAAACAkQBADs=">
<link rel="stylesheet" href="test-stylesheet.css">
- <script src="test-document2-script.js"></script>
+ <script src="js/html-test-utilities.js"></script>
+ <script src="js/popup-tests.js"></script>
+ <style id="container-styles">
+.container {
+ width: 100%;
+ height: 200px;
+ border: 1px solid #d8d8d8;
+ position: relative;
+ box-sizing: border-box;
+}
+
+.container-inner {
+ background-color: #f8f8f8;
+ padding: 0.5em;
+ position: absolute;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ right: 0;
+}
+
+.danger {
+ color: #c83c28;
+}
+ </style>
</head>
-<style id="container-styles">
- .container {
- width: 100%;
- height: 200px;
- border: 1px solid #d8d8d8;
- position: relative;
- box-sizing: border-box;
- }
-
- .container-inner {
- background-color: #f8f8f8;
- padding: 0.5em;
- position: absolute;
- left: 0;
- top: 0;
- bottom: 0;
- right: 0;
- }
-
- .danger {
- color: #c83c28;
- }
-
-</style>
-
<body>
+ <h1>Popup Tests</h1>
- <h1>Yomitan Manual Tests</h1>
- <y-description>Manual tests involving fullscreen elements, &lt;iframe&gt;s, and shadow DOMs.</y-description>
+ <test-description>
+ Tests involving popup functionality in different contextsts, such as fullscreen elements, &lt;iframe&gt; elements, and shadow DOMs.
+ </test-description>
- <y-test>
- <y-description>Standard content.</y-description>
+ <test-case>
+ <test-description>Standard content.</test-description>
<div class="fullscreen-element container hovertarget">
<div class="container-inner">
<div>
@@ -52,10 +51,10 @@
</div>
</div>
</div>
- </y-test>
+ </test-case>
- <y-test data-shadow-mode="open">
- <y-description>Content inside of an open shadow DOM.</y-description>
+ <test-case data-shadow-mode="open">
+ <test-description>Content inside of an open shadow DOM.</test-description>
<div class="template-content-container hovertarget"></div>
<template>
<link rel="stylesheet" href="test-stylesheet.css">
@@ -70,10 +69,10 @@
</div>
</div>
</template>
- </y-test>
+ </test-case>
- <y-test data-shadow-mode="closed">
- <y-description>Content inside of a closed shadow DOM.</y-description>
+ <test-case data-shadow-mode="closed">
+ <test-description>Content inside of a closed shadow DOM.</test-description>
<div class="template-content-container hovertarget"></div>
<template>
<link rel="stylesheet" href="test-stylesheet.css">
@@ -88,84 +87,84 @@
</div>
</div>
</template>
- </y-test>
+ </test-case>
- <y-test>
- <y-description>&lt;iframe&gt; element.</y-description>
- <iframe src="test-document2-frame1.html" allowfullscreen="true" class="container hovertarget"></iframe>
- </y-test>
+ <test-case>
+ <test-description>&lt;iframe&gt; element.</test-description>
+ <iframe src="popup-tests-frame1.html" allowfullscreen="true" class="container hovertarget"></iframe>
+ </test-case>
- <y-test data-shadow-mode="open">
- <y-description>&lt;iframe&gt; element inside of an open shadow DOM.</y-description>
+ <test-case data-shadow-mode="open">
+ <test-description>&lt;iframe&gt; element inside of an open shadow DOM.</test-description>
<div class="template-content-container hovertarget"></div>
<template>
- <iframe src="test-document2-frame1.html" allowfullscreen="true" class="container"></iframe>
+ <iframe src="popup-tests-frame1.html" allowfullscreen="true" class="container"></iframe>
</template>
- </y-test>
+ </test-case>
- <y-test data-shadow-mode="closed">
- <y-description>&lt;iframe&gt; element inside of a closed shadow DOM.</y-description>
+ <test-case data-shadow-mode="closed">
+ <test-description>&lt;iframe&gt; element inside of a closed shadow DOM.</test-description>
<div class="template-content-container hovertarget"></div>
<template>
- <iframe src="test-document2-frame1.html" allowfullscreen="true" class="container"></iframe>
+ <iframe src="popup-tests-frame1.html" allowfullscreen="true" class="container"></iframe>
</template>
- </y-test>
+ </test-case>
- <y-test>
- <y-description>&lt;iframe&gt; element with data URL.</y-description>
+ <test-case>
+ <test-description>&lt;iframe&gt; element with data URL.</test-description>
<iframe id="iframe-with-data-url"
src="data:text/html;base64,PCFET0NUWVBFIGh0bWw+DQo8aHRtbD4NCiAgICA8aGVhZD4NCiAgICAgICAgPG1ldGEgY2hhcnNldD0iVVRGLTgiPg0KICAgICAgICA8bWV0YSBuYW1lPSJ2aWV3cG9ydCIgY29udGVudD0id2lkdGg9ZGV2aWNlLXdpZHRoLGluaXRpYWwtc2NhbGU9MSI+DQogICAgICAgIDx0aXRsZT5Zb21pY2hhbiBUZXN0czwvdGl0bGU+DQogICAgICAgIDxzY3JpcHQ+DQogZnVuY3Rpb24gcmVxdWVzdEZ1bGxzY3JlZW4oZWxlbWVudCkgew0KICAgIGlmIChlbGVtZW50LnJlcXVlc3RGdWxsc2NyZWVuKSB7DQogICAgICAgIGVsZW1lbnQucmVxdWVzdEZ1bGxzY3JlZW4oKTsNCiAgICB9IGVsc2UgaWYgKGVsZW1lbnQubW96UmVxdWVzdEZ1bGxTY3JlZW4pIHsNCiAgICAgICAgZWxlbWVudC5tb3pSZXF1ZXN0RnVsbFNjcmVlbigpOw0KICAgIH0gZWxzZSBpZiAoZWxlbWVudC53ZWJraXRSZXF1ZXN0RnVsbHNjcmVlbikgew0KICAgICAgICBlbGVtZW50LndlYmtpdFJlcXVlc3RGdWxsc2NyZWVuKCk7DQogICAgfSBlbHNlIGlmIChlbGVtZW50Lm1zUmVxdWVzdEZ1bGxzY3JlZW4pIHsNCiAgICAgICAgZWxlbWVudC5tc1JlcXVlc3RGdWxsc2NyZWVuKCk7DQogICAgfQ0KfQ0KDQpmdW5jdGlvbiBleGl0RnVsbHNjcmVlbigpIHsNCiAgICBpZiAoZG9jdW1lbnQuZXhpdEZ1bGxzY3JlZW4pIHsNCiAgICAgICAgZG9jdW1lbnQuZXhpdEZ1bGxzY3JlZW4oKTsNCiAgICB9IGVsc2UgaWYgKGRvY3VtZW50Lm1vekNhbmNlbEZ1bGxTY3JlZW4pIHsNCiAgICAgICAgZG9jdW1lbnQubW96Q2FuY2VsRnVsbFNjcmVlbigpOw0KICAgIH0gZWxzZSBpZiAoZG9jdW1lbnQud2Via2l0RXhpdEZ1bGxzY3JlZW4pIHsNCiAgICAgICAgZG9jdW1lbnQud2Via2l0RXhpdEZ1bGxzY3JlZW4oKTsNCiAgICB9IGVsc2UgaWYgKGRvY3VtZW50Lm1zRXhpdEZ1bGxzY3JlZW4pIHsNCiAgICAgICAgZG9jdW1lbnQubXNFeGl0RnVsbHNjcmVlbigpOw0KICAgIH0NCn0NCg0KZnVuY3Rpb24gZ2V0RnVsbHNjcmVlbkVsZW1lbnQoKSB7DQogICAgcmV0dXJuICgNCiAgICAgICAgZG9jdW1lbnQuZnVsbHNjcmVlbkVsZW1lbnQgfHwNCiAgICAgICAgZG9jdW1lbnQubXNGdWxsc2NyZWVuRWxlbWVudCB8fA0KICAgICAgICBkb2N1bWVudC5tb3pGdWxsU2NyZWVuRWxlbWVudCB8fA0KICAgICAgICBkb2N1bWVudC53ZWJraXRGdWxsc2NyZWVuRWxlbWVudCB8fA0KICAgICAgICBudWxsDQogICAgKTsNCn0NCg0KZnVuY3Rpb24gdG9nZ2xlRnVsbHNjcmVlbihlbGVtZW50KSB7DQogICAgaWYgKGdldEZ1bGxzY3JlZW5FbGVtZW50KCkpIHsNCiAgICAgICAgZXhpdEZ1bGxzY3JlZW4oKTsNCiAgICB9IGVsc2Ugew0KICAgICAgICByZXF1ZXN0RnVsbHNjcmVlbihlbGVtZW50KTsNCiAgICB9DQp9DQoNCmZ1bmN0aW9uIHNldHVwKGNvbnRhaW5lciwgZnVsbHNjcmVlbkVsZW1lbnQ9bnVsbCkgew0KICAgIGNvbnN0IGZ1bGxzY3JlZW5MaW5rID0gY29udGFpbmVyLnF1ZXJ5U2VsZWN0b3IoJy5mdWxsc2NyZWVuLWxpbmsnKTsNCiAgICBpZiAoZnVsbHNjcmVlbkxpbmsgIT09IG51bGwpIHsNCiAgICAgICAgaWYgKGZ1bGxzY3JlZW5FbGVtZW50ID09PSBudWxsKSB7DQogICAgICAgICAgICBmdWxsc2NyZWVuRWxlbWVudCA9IGNvbnRhaW5lci5xdWVyeVNlbGVjdG9yKCcuZnVsbHNjcmVlbi1lbGVtZW50Jyk7DQogICAgICAgIH0NCiAgICAgICAgZnVsbHNjcmVlbkxpbmsuYWRkRXZlbnRMaXN0ZW5lcignY2xpY2snLCAoZSkgPT4gew0KICAgICAgICAgICAgdG9nZ2xlRnVsbHNjcmVlbihmdWxsc2NyZWVuRWxlbWVudCk7DQogICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7DQogICAgICAgICAgICByZXR1cm4gZmFsc2U7DQogICAgICAgIH0sIGZhbHNlKTsNCiAgICB9DQoNCiAgICBjb25zdCB0ZW1wbGF0ZSA9IGNvbnRhaW5lci5xdWVyeVNlbGVjdG9yKCd0ZW1wbGF0ZScpOw0KICAgIGNvbnN0IHRlbXBsYXRlQ29udGVudENvbnRhaW5lciA9IGNvbnRhaW5lci5xdWVyeVNlbGVjdG9yKCcudGVtcGxhdGUtY29udGVudC1jb250YWluZXInKTsNCiAgICBpZiAodGVtcGxhdGUgIT09IG51bGwgJiYgdGVtcGxhdGVDb250ZW50Q29udGFpbmVyICE9PSBudWxsKSB7DQogICAgICAgIGNvbnN0IG1vZGUgPSBjb250YWluZXIuZGF0YXNldC5zaGFkb3dNb2RlOw0KICAgICAgICBjb25zdCBzaGFkb3cgPSB0ZW1wbGF0ZUNvbnRlbnRDb250YWluZXIuYXR0YWNoU2hhZG93KHttb2RlfSk7DQoNCiAgICAgICAgY29uc3QgY29udGFpbmVyU3R5bGVzID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignI2NvbnRhaW5lci1zdHlsZXMnKTsNCiAgICAgICAgc2hhZG93LmFwcGVuZENoaWxkKGNvbnRhaW5lclN0eWxlcy5jbG9uZU5vZGUodHJ1ZSkpOw0KDQogICAgICAgIGNvbnN0IGNvbnRlbnQgPSBkb2N1bWVudC5pbXBvcnROb2RlKHRlbXBsYXRlLmNvbnRlbnQsIHRydWUpOw0KICAgICAgICBzZXR1cChjb250ZW50KTsNCiAgICAgICAgc2hhZG93LmFwcGVuZENoaWxkKGNvbnRlbnQpOw0KICAgIH0NCn0NCiAgICAgICAgPC9zY3JpcHQ+DQogICAgICAgIDxzdHlsZT4NCmJvZHkgew0KICAgIGZvbnQtZmFtaWx5OiAiSGVsdmV0aWNhIE5ldWUiLCBIZWx2ZXRpY2EsIEFyaWFsLCBzYW5zLXNlcmlmOw0KICAgIGZvbnQtc2l6ZTogMTRweDsNCiAgICBwYWRkaW5nOiAwOw0KICAgIG1hcmdpbjogMDsNCiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjZjhmOGY4Ow0KfQ0KYSwgYTp2aXNpdGVkIHsNCiAgICBjb2xvcjogIzEwODBjMDsNCiAgICB0ZXh0LWRlY29yYXRpb246IHVuZGVybGluZTsNCn0NCi5jb250ZW50IHsNCiAgICBwb3NpdGlvbjogYWJzb2x1dGU7DQogICAgbGVmdDogMDsNCiAgICB0b3A6IDA7DQogICAgcmlnaHQ6IDA7DQogICAgYm90dG9tOiAwOw0KICAgIHBhZGRpbmc6IDAuNWVtOw0KICAgIGJhY2tncm91bmQtY29sb3I6ICNmOGY4Zjg7DQp9DQogICAgICAgIDwvc3R5bGU+DQogICAgPC9oZWFkPg0KPGJvZHk+PGRpdiBjbGFzcz0iY29udGVudCI+DQo8ZGl2Pg0KICAgIOOBguOCiuOBjOOBqOOBhg0KPC9kaXY+DQo8ZGl2Pg0KICAgIDxhIGhyZWY9IiMiIGNsYXNzPSJmdWxsc2NyZWVuLWxpbmsiPlRvZ2dsZSBmdWxsc2NyZWVuPC9hPg0KICAgIDxzY3JpcHQ+c2V0dXAoZG9jdW1lbnQuYm9keSwgZG9jdW1lbnQuYm9keSk7PC9zY3JpcHQ+DQo8L2Rpdj4NCjwvZGl2PjwvYm9keT4NCjwvaHRtbD4="
allowfullscreen="true" class="container hovertarget"></iframe>
- </y-test>
+ </test-case>
- <y-test>
- <y-description>&lt;iframe&gt; element with blob URL.</y-description>
+ <test-case>
+ <test-description>&lt;iframe&gt; element with blob URL.</test-description>
<iframe id="iframe-with-blob-url" allowfullscreen="true" class="container hovertarget"></iframe>
- </y-test>
+ </test-case>
- <y-test>
- <y-description>&lt;iframe&gt; element with srcdoc.</y-description>
+ <test-case>
+ <test-description>&lt;iframe&gt; element with srcdoc.</test-description>
<iframe allowfullscreen="true" class="iframe-with-srcdoc container hovertarget"></iframe>
- </y-test>
+ </test-case>
- <y-test>
- <y-description>&lt;iframe&gt; element with srcdoc and
- <code>sandbox="allow-same-origin allow-scripts"</code>.</y-description>
+ <test-case>
+ <test-description>&lt;iframe&gt; element with srcdoc and
+ <code>sandbox="allow-same-origin allow-scripts"</code>.</test-description>
<iframe allowfullscreen="true" class="iframe-with-srcdoc container hovertarget"
sandbox="allow-same-origin allow-scripts"></iframe>
- </y-test>
+ </test-case>
- <y-test>
- <y-description>
+ <test-case>
+ <test-description>
&lt;iframe&gt; element with srcdoc and <code>sandbox="allow-scripts"</code>.<br>
<span class="danger">This element is expected to not work.</span>
- </y-description>
+ </test-description>
<iframe allowfullscreen="true" class="iframe-with-srcdoc container hovertarget"
sandbox="allow-scripts"></iframe>
- </y-test>
-
- <y-test>
- <y-description>SVG &lt;img&gt;.</y-description>
- <img src="test-document2-frame2.svg" class="container hovertarget" alt="">
- </y-test>
-
- <y-test>
- <y-description>SVG &lt;object&gt;.</y-description>
- <object data="test-document2-frame2.svg" type="image/svg+xml" class="container hovertarget"></object>
- </y-test>
-
- <y-test>
- <y-description>SVG &lt;embed&gt;.</y-description>
- <embed type="image/svg+xml" src="test-document2-frame2.svg" class="container hovertarget">
- </y-test>
-
- <y-test>
- <y-description>SVG &lt;iframe&gt;.</y-description>
- <iframe src="test-document2-frame2.svg" allowfullscreen="true" class="container hovertarget"></iframe>
- </y-test>
-
- <y-test>
- <y-description>SVG &lt;svg&gt;.</y-description>
+ </test-case>
+
+ <test-case>
+ <test-description>SVG &lt;img&gt;.</test-description>
+ <img src="popup-tests-frame2.svg" class="container hovertarget" alt="">
+ </test-case>
+
+ <test-case>
+ <test-description>SVG &lt;object&gt;.</test-description>
+ <object data="popup-tests-frame2.svg" type="image/svg+xml" class="container hovertarget"></object>
+ </test-case>
+
+ <test-case>
+ <test-description>SVG &lt;embed&gt;.</test-description>
+ <embed type="image/svg+xml" src="popup-tests-frame2.svg" class="container hovertarget">
+ </test-case>
+
+ <test-case>
+ <test-description>SVG &lt;iframe&gt;.</test-description>
+ <iframe src="popup-tests-frame2.svg" allowfullscreen="true" class="container hovertarget"></iframe>
+ </test-case>
+
+ <test-case>
+ <test-description>SVG &lt;svg&gt;.</test-description>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" class="container hovertarget"
style="background-color: #f8f8f8;" focusable="false">
<text x="7" y="12" style="
@@ -176,47 +175,6 @@
ありがとう
</text>
</svg>
- </y-test>
-
-
- <script>
- (() => {
- function stringToTypedArray(string) {
- const array = new Uint8Array(string.length);
- for (let i = 0; i < string.length; ++i) {
- array[i] = string.charCodeAt(i);
- }
- return array;
- }
-
- function dataUrlToContent(dataUrl) {
- const [, type, isBase64, data] = /^data:([^;]*);(base64,)?([\w\W]*)$/.exec(dataUrl);
- const content = (
- isBase64 ?
- new TextDecoder().decode(stringToTypedArray(atob(data))) :
- data
- );
- return { content, type };
- }
-
- function dataUrlToBlob(dataUrl) {
- const { content, type } = dataUrlToContent(dataUrl);
- return new Blob([content], { type });
- }
-
- for (const element of document.querySelectorAll('y-test')) {
- setup(element);
- }
-
- const iframeWithDataUrl = document.querySelector('#iframe-with-data-url');
- const iframeWithBlobUrl = document.querySelector('#iframe-with-blob-url');
- iframeWithBlobUrl.src = URL.createObjectURL(dataUrlToBlob(iframeWithDataUrl.src));
- for (const iframeWithSrcdoc of document.querySelectorAll('.iframe-with-srcdoc')) {
- iframeWithSrcdoc.srcdoc = dataUrlToContent(iframeWithDataUrl.src).content;
- }
- })();
- </script>
-
+ </test-case>
</body>
-
</html>
diff --git a/test/data/html/test-document2-script.js b/test/data/html/test-document2-script.js
deleted file mode 100644
index d8e1278d..00000000
--- a/test/data/html/test-document2-script.js
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2023 Yomitan Authors
- * Copyright (C) 2021-2022 Yomichan Authors
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
-
-/**
- * @param {Element} element
- */
-function requestFullscreen(element) {
- if (element.requestFullscreen) {
- element.requestFullscreen();
- // @ts-expect-error - Browser compatibility
- } else if (element.mozRequestFullScreen) {
- // @ts-expect-error - Browser compatibility
- element.mozRequestFullScreen();
- // @ts-expect-error - Browser compatibility
- } else if (element.webkitRequestFullscreen) {
- // @ts-expect-error - Browser compatibility
- element.webkitRequestFullscreen();
- // @ts-expect-error - Browser compatibility
- } else if (element.msRequestFullscreen) {
- // @ts-expect-error - Browser compatibility
- element.msRequestFullscreen();
- }
-}
-
-/** */
-function exitFullscreen() {
- if (document.exitFullscreen) {
- document.exitFullscreen();
- // @ts-expect-error - Browser compatibility
- } else if (document.mozCancelFullScreen) {
- // @ts-expect-error - Browser compatibility
- document.mozCancelFullScreen();
- // @ts-expect-error - Browser compatibility
- } else if (document.webkitExitFullscreen) {
- // @ts-expect-error - Browser compatibility
- document.webkitExitFullscreen();
- // @ts-expect-error - Browser compatibility
- } else if (document.msExitFullscreen) {
- // @ts-expect-error - Browser compatibility
- document.msExitFullscreen();
- }
-}
-
-/**
- * @returns {?Element}
- */
-function getFullscreenElement() {
- return (
- document.fullscreenElement ||
- // @ts-expect-error - Browser compatibility
- document.msFullscreenElement ||
- // @ts-expect-error - Browser compatibility
- document.mozFullScreenElement ||
- // @ts-expect-error - Browser compatibility
- document.webkitFullscreenElement ||
- null
- );
-}
-
-/**
- * @param {Element} element
- */
-function toggleFullscreen(element) {
- if (getFullscreenElement()) {
- exitFullscreen();
- } else {
- requestFullscreen(element);
- }
-}
-
-/**
- * @param {HTMLElement|DocumentFragment} container
- * @param {?Element} [fullscreenElement]
- */
-function setup(container, fullscreenElement = null) {
- const fullscreenLink = container.querySelector('.fullscreen-link');
- if (fullscreenLink !== null) {
- if (fullscreenElement === null) {
- fullscreenElement = container.querySelector('.fullscreen-element');
- }
- fullscreenLink.addEventListener('click', (e) => {
- if (fullscreenElement === null) { return; }
- toggleFullscreen(fullscreenElement);
- e.preventDefault();
- return false;
- }, false);
- }
-
- const template = container.querySelector('template');
- const templateContentContainer = container.querySelector('.template-content-container');
- if (template !== null && templateContentContainer !== null) {
- const mode = (container instanceof HTMLElement ? container.dataset.shadowMode : void 0);
- const shadow = templateContentContainer.attachShadow({
- mode: (mode === 'open' || mode === 'closed' ? mode : 'open')
- });
-
- const containerStyles = document.querySelector('#container-styles');
- if (containerStyles !== null) {
- shadow.appendChild(containerStyles.cloneNode(true));
- }
-
- const content = document.importNode(template.content, true);
- setup(content);
- shadow.appendChild(content);
- }
-}
diff --git a/test/data/html/test-document3-frame1.html b/test/data/html/test-document3-frame1.html
deleted file mode 100644
index 83f82c6e..00000000
--- a/test/data/html/test-document3-frame1.html
+++ /dev/null
@@ -1,44 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width,initial-scale=1">
- <title>Yomitan Manual Performance Tests</title>
- <link rel="stylesheet" href="test-stylesheet.css">
- </head>
-<body><div class="content">
-
- <div class="description">Add elements</div>
-
- <div>
- <a href="#" id="add-elements-1000">1000</a>
- <a href="#" id="add-elements-10000">10000</a>
- <a href="#" id="add-elements-100000">100000</a>
- <a href="#" id="add-elements-1000000">1000000</a>
- <script>
-document.querySelector('#add-elements-1000').addEventListener('click', () => addElements(1000), false);
-document.querySelector('#add-elements-10000').addEventListener('click', () => addElements(10000), false);
-document.querySelector('#add-elements-100000').addEventListener('click', () => addElements(100000), false);
-document.querySelector('#add-elements-1000000').addEventListener('click', () => addElements(1000000), false);
-
-let counter = 0;
-
-function addElements(amount) {
- const container = document.querySelector('#container');
- for (let i = 0; i < amount; i++) {
- const element = document.createElement('div');
- element.textContent = 'ありがとう';
- container.appendChild(element);
- }
-
- counter += amount;
- document.querySelector('#counter').textContent = counter;
-}
- </script>
- </div>
-
- <div id="counter"></div>
- <div id="container"></div>
-
-</div></body>
-</html>
diff --git a/test/data/html/test-document3-frame2.html b/test/data/html/test-document3-frame2.html
deleted file mode 100644
index d947715d..00000000
--- a/test/data/html/test-document3-frame2.html
+++ /dev/null
@@ -1,62 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width,initial-scale=1">
- <title>Yomitan Manual Performance Tests</title>
- <link rel="stylesheet" href="test-stylesheet.css">
- </head>
-<body><div class="content">
-
- <div class="description">&lt;iframe&gt; element inside of an open shadow DOM.</div>
-
- <div id="shadow-iframe-container-open"></div>
- <template id="shadow-iframe-container-open-content-template">
- <iframe src="test-document2-frame1.html" allowfullscreen="true" style="width: 100%; height: 50px; border: 1px solid #d8d8d8;"></iframe>
- </template>
- <script>
-(() => {
- const shadowIframeContainer = document.querySelector('#shadow-iframe-container-open');
- const shadow = shadowIframeContainer.attachShadow({mode: 'open'});
- const template = document.querySelector('#shadow-iframe-container-open-content-template').content;
- const content = document.importNode(template, true);
- shadow.appendChild(content);
-})();
- </script>
-
- <div class="description">Add elements</div>
-
- <div>
- <a href="#" id="add-elements-1000">1000</a>
- <a href="#" id="add-elements-10000">10000</a>
- <a href="#" id="add-elements-100000">100000</a>
- <a href="#" id="add-elements-1000000">1000000</a>
- </div>
-
- <div id="counter"></div>
- <div id="container"></div>
- <script>
-(() => {
- document.querySelector('#add-elements-1000').addEventListener('click', () => addElements(1000), false);
- document.querySelector('#add-elements-10000').addEventListener('click', () => addElements(10000), false);
- document.querySelector('#add-elements-100000').addEventListener('click', () => addElements(100000), false);
- document.querySelector('#add-elements-1000000').addEventListener('click', () => addElements(1000000), false);
-
- let counter = 0;
-
- function addElements(amount) {
- const container = document.querySelector('#container');
- for (let i = 0; i < amount; i++) {
- const element = document.createElement('div');
- element.textContent = 'ありがとう';
- container.appendChild(element);
- }
-
- counter += amount;
- document.querySelector('#counter').textContent = counter;
- }
-})();
- </script>
-
-</div></body>
-</html>
diff --git a/test/data/html/test-document3.html b/test/data/html/test-document3.html
deleted file mode 100644
index 218e211a..00000000
--- a/test/data/html/test-document3.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width,initial-scale=1">
- <title>Yomitan Manual Performance Tests</title>
- <link rel="icon" type="image/gif" href="data:image/gif;base64,R0lGODlhEAAQAKEBAAAAAP///////////yH5BAEKAAIALAAAAAAQABAAAAImFI6Zpt0B4YkS0TCpq07xbmEgcGVRUpLaI46ZG7ppalY0jDCwUAAAOw==">
- <link rel="stylesheet" href="test-stylesheet.css">
- </head>
-<body>
-
- <h1>Yomitan Manual Performance Tests</h1>
- <p class="description">Testing Yomitan performance with artificially demanding cases in a real browser</p>
-
- <div class="test">
- <div class="description">&lt;iframe&gt; element.</div>
- <iframe src="test-document3-frame1.html" allowfullscreen="true" style="width: 100%; height: 200px; border: 1px solid #d8d8d8;"></iframe>
- </div>
-
- <div class="test">
- <div class="description">&lt;iframe&gt; element containing an &lt;iframe&gt; element inside of an open shadow DOM.</div>
- <iframe src="test-document3-frame2.html" allowfullscreen="true" style="width: 100%; height: 200px; border: 1px solid #d8d8d8;"></iframe>
- </div>
-
-</body>
-</html>
diff --git a/test/data/html/test-stylesheet.css b/test/data/html/test-stylesheet.css
index 0d7a0f2e..7a97b523 100644
--- a/test/data/html/test-stylesheet.css
+++ b/test/data/html/test-stylesheet.css
@@ -19,8 +19,7 @@ p {
margin: 0.33em 0;
}
-h1+p,
-h1+y-description {
+h1+test-description {
margin-top: -0.67em;
}
@@ -29,8 +28,7 @@ a, a:visited {
text-decoration: underline;
}
-.test,
-y-test {
+test-case {
display: block;
background-color: #ffffff;
margin: 1em 0;
@@ -39,8 +37,7 @@ y-test {
border-radius: 4px;
}
-.test::before,
-y-test::before {
+test-case::before {
content: 'Test ' counter(test-id);
display: block;
counter-increment: test-id;
@@ -49,8 +46,7 @@ y-test::before {
font-weight: bold;
}
-.description,
-y-description {
+test-description {
color: #444444;
font-style: italic;
display: block;
diff --git a/test/document-util.test.js b/test/document-util.test.js
index 51872422..5f2e49ea 100644
--- a/test/document-util.test.js
+++ b/test/document-util.test.js
@@ -109,7 +109,7 @@ function findImposterElement(document) {
return document.querySelector('div[style*="2147483646"]>*');
}
-const test = createDomTest(path.join(dirname, 'data/html/test-document1.html'));
+const test = createDomTest(path.join(dirname, 'data/html/document-util.html'));
describe('DocumentUtil', () => {
test('Text scanning functions', ({window}) => {
diff --git a/test/dom-text-scanner.test.js b/test/dom-text-scanner.test.js
index f53e326d..da38d24c 100644
--- a/test/dom-text-scanner.test.js
+++ b/test/dom-text-scanner.test.js
@@ -102,14 +102,14 @@ function createAbsoluteGetComputedStyle(window) {
}
-const test = createDomTest(path.join(dirname, 'data/html/test-dom-text-scanner.html'));
+const test = createDomTest(path.join(dirname, 'data/html/dom-text-scanner.html'));
describe('DOMTextScanner', () => {
test('Seek tests', ({window}) => {
const {document} = window;
window.getComputedStyle = createAbsoluteGetComputedStyle(window);
- for (const testElement of /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll('y-test'))) {
+ for (const testElement of /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll('test-case'))) {
/** @type {import('test/dom-text-scanner').TestData|import('test/dom-text-scanner').TestData[]} */
let testData = parseJson(/** @type {string} */ (testElement.dataset.testData));
if (!Array.isArray(testData)) {
diff --git a/test/playwright/visual.spec.js b/test/playwright/visual.spec.js
index b912f8b4..02efc985 100644
--- a/test/playwright/visual.spec.js
+++ b/test/playwright/visual.spec.js
@@ -16,12 +16,8 @@
*/
import path from 'path';
-
-import {
- expect,
- root,
- test
-} from './playwright-util';
+import {pathToFileURL} from 'url';
+import {expect, root, test} from './playwright-util';
test.beforeEach(async ({context}) => {
// wait for the on-install welcome.html tab to load, which becomes the foreground tab
@@ -86,8 +82,8 @@ test('visual', async ({page, extensionId}) => {
await (await /** @type {import('@playwright/test').Frame} */ (popup_frame).frameElement()).waitForElementState('hidden'); // wait for popup to disappear
};
- // Load test-document1.html
- await page.goto('file://' + path.join(root, 'test/data/html/test-document1.html'));
+ // Test document 1
+ await page.goto(pathToFileURL(path.join(root, 'test/data/html/document-util.html')).toString());
await page.setViewportSize({width: 1000, height: 1800});
await page.keyboard.down('Shift');
let i = 1;
@@ -96,8 +92,8 @@ test('visual', async ({page, extensionId}) => {
i++;
}
- // Load test-document2.html
- await page.goto('file://' + path.join(root, 'test/data/html/test-document2.html'));
+ // Test document 2
+ await page.goto(pathToFileURL(path.join(root, 'test/data/html/popup-tests.html')).toString());
await page.setViewportSize({width: 1000, height: 4500});
await page.keyboard.down('Shift');
i = 1;