diff --git a/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-noopener.html b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-noopener.html
index c31e75fdf57e1..c955e677899ed 100644
--- a/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-noopener.html
+++ b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-noopener.html
@@ -5,158 +5,7 @@
+
diff --git a/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-noreferrer.html b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-noreferrer.html
new file mode 100644
index 0000000000000..4807f634fdac8
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/open-features-tokenization-noreferrer.html
@@ -0,0 +1,11 @@
+
+
+
HTML: window.open `features`: tokenization -- `noreferrer`
+
+
+
+
+
+
diff --git a/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/resources/tokenization-noopener-noreferrer.js b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/resources/tokenization-noopener-noreferrer.js
new file mode 100644
index 0000000000000..a9d42e26dea16
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/resources/tokenization-noopener-noreferrer.js
@@ -0,0 +1,152 @@
+function booleanTests(feature) {
+ const windowURL = 'resources/close-self.html';
+ // Tests for how windows features are tokenized into 'name', 'value'
+ // window features separators are ASCII whitespace, '=' and ','
+
+ const featureUpper = feature.toUpperCase(),
+ featureSplitBegin = feature.slice(0, 2),
+ featureSplitEnd = feature.slice(2),
+ featureMixedCase = featureSplitBegin.toUpperCase() + featureSplitEnd;
+ featureMixedCase2 = featureSplitBegin + featureSplitEnd.toUpperCase();
+
+ test (t => {
+ // Tokenizing `name`: initial window features separators are ignored
+ // Each of these variants should tokenize to (`${feature}`, '')
+ [
+ ` ${feature}`,
+ `=${feature}`,
+ `,,${feature}`,
+ `,=, ${feature}`,
+ `\n=${feature}=`,
+ `\t${feature}`,
+ `\r,,,=${feature}`,
+ `\u000C${feature}`
+ ].forEach(variant => {
+ const win = window.open(windowURL, "", variant);
+ assert_equals(win, null, `"${variant}" should activate feature "${feature}"`);
+ });
+ }, `Tokenization of "${feature}" should skip window features separators before feature`);
+
+ test (t => {
+ // Tokenizing `name`: lowercase conversion
+ // Each of these variants should tokenize as feature (`${feature}`, '')
+ // except where indicated
+ // Note also that `value` is lowercased during tokenization
+ [
+ `${featureUpper}`,
+ `${featureMixedCase}`,
+ ` ${featureMixedCase2}`,
+ `=${featureUpper}`,
+ `${featureUpper}=1`,
+ `${featureUpper}=1`,
+ `${featureUpper}=yes`,
+ `${feature}=YES`,
+ ].forEach(variant => {
+ const win = window.open(windowURL, '', variant);
+ assert_equals(win, null, `"${variant}" should activate feature "${feature}"`);
+ });
+ }, `Feature "${feature}" should be converted to ASCII lowercase`);
+
+ test (t => {
+ // After `name` has been collected, ignore any window features separators until '='
+ // except ',' OR a non-window-features-separator — break in those cases
+ // i.e. ignore whitespace until '=' unless a ',' is encountered first
+ // Each of these variants should tokenize as feature ('noopener', '')
+ [
+ `${feature}`,
+ ` ${feature}\r`,
+ `${feature}\n =`,
+ `${feature},`,
+ `${feature} =,`,
+ `, ${feature} =`,
+ `${feature},=`,
+ `${feature} foo`,
+ `foo ${feature}=1`,
+ `foo=\u000Cbar\u000C${feature}`
+ ].forEach(variant => {
+ const win = window.open(windowURL, '', variant);
+ assert_equals(win, null, `"${variant}" should activate feature "${feature}"`);
+ });
+ }, `After "${feature}", tokenization should skip window features separators that are not "=" or ","`);
+
+ test (t => {
+ // After initial '=', tokenizing should ignore all separators except ','
+ // before collecting `value`
+ // Each of these variants should tokenize as feature ('noopener', '')
+ // Except where indicated
+ [
+ `${feature}= yes`,
+ `${feature}==,`,
+ `${feature}=\n ,`,
+ `${feature} = \t ,`,
+ `${feature}\n=\r 1,`,
+ `${feature}=,yes`,
+ `${feature}= yes=,`,
+ `${feature} = \u000Cyes`
+ ].forEach(variant => {
+ const win = window.open(windowURL, '', variant);
+ assert_equals(win, null, `"${variant}" should activate feature "${feature}"`);
+ });
+ }, `Tokenizing "${feature}" should ignore window feature separators except "," after initial "=" and before value`);
+
+ test (t => {
+ // Tokenizing `value` should collect any non-separator code points until first separator
+ [
+ `${feature}=1`,
+ `${feature}=yes`,
+ `${feature} = yes ,`,
+ `${feature}=\nyes ,`,
+ `${feature}=yes yes`,
+ `${feature}=yes\ts`,
+ `${feature}==`,
+ `${feature}=1\n,`,
+ `==${feature}===`,
+ `${feature}==\u000C`
+ ].forEach(variant => {
+ const win = window.open(windowURL, '', variant);
+ assert_equals(win, null, `"${variant}" should set "${feature}"`);
+ });
+ }, `Tokenizing "${feature}" should read characters until first window feature separator as \`value\``);
+
+ test (t => {
+ [
+ `${feature}=1`,
+ `${feature}=2`,
+ `${feature}=12345`,
+ `${feature}=1.5`,
+ `${feature}=-1`,
+ ].forEach(variant => {
+ const win = window.open(windowURL, '', variant);
+ assert_equals(win, null, `"${variant}" should activate feature "${feature}"`);
+ });
+ }, 'Integer values other than 0 should activate the feature');
+
+ test (t => {
+ [
+ `${feature}=0`,
+ `${feature}=0.5`,
+ `${feature}=error`,
+ ].forEach(variant => {
+ const win = window.open(windowURL, '', variant);
+ assert_not_equals(win, null, `"${variant}" should NOT activate feature "${feature}"`);
+ });
+ }, `Integer value of 0 should not activate "${feature}"`);
+
+ test (t => {
+ [
+ `-${feature}`,
+ `${featureUpper}RRR`,
+ `${featureMixedCase}R`,
+ `${featureSplitBegin}_${featureSplitEnd}`,
+ ` ${featureSplitBegin} ${featureSplitEnd}`,
+ `${featureSplitBegin}\n${featureSplitEnd}`,
+ `${featureSplitBegin},${featureSplitEnd}`,
+ `\0${feature}`,
+ `${feature}\u0000=yes`,
+ `foo=\u000C${feature}`
+ ].forEach(variant => {
+ const win = window.open(windowURL, '', variant);
+ assert_not_equals(win, null, `"${variant}" should NOT activate feature "${feature}"`);
+ });
+ }, `Invalid feature names should not tokenize as "${feature}"`);
+}
diff --git a/testing/web-platform/tests/html/browsers/the-window-object/support/noreferrer-target.html b/testing/web-platform/tests/html/browsers/the-window-object/support/noreferrer-target.html
new file mode 100644
index 0000000000000..c2446c6fe958a
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/the-window-object/support/noreferrer-target.html
@@ -0,0 +1,13 @@
+
diff --git a/testing/web-platform/tests/html/browsers/the-window-object/window-open-noreferrer.html b/testing/web-platform/tests/html/browsers/the-window-object/window-open-noreferrer.html
new file mode 100644
index 0000000000000..92b72cdb5f1ec
--- /dev/null
+++ b/testing/web-platform/tests/html/browsers/the-window-object/window-open-noreferrer.html
@@ -0,0 +1,20 @@
+
+
+window.open() with "noreferrer" tests
+
+
+