{ "comment": [ "## Tests for setters of https://url.spec.whatwg.org/#urlutils-members", "", "This file contains a JSON object.", "Other than 'comment', each key is an attribute of the `URL` interface", "defined in WHATWG’s URL Standard.", "The values are arrays of test case objects for that attribute.", "", "To run a test case for the attribute `attr`:", "", "* Create a new `URL` object with the value for the 'href' key", " the constructor single parameter. (Without a base URL.)", " This must not throw.", "* Set the attribute `attr` to (invoke its setter with)", " with the value of for 'new_value' key.", "* The value for the 'expected' key is another object.", " For each `key` / `value` pair of that object,", " get the attribute `key` (invoke its getter).", " The returned string must be equal to `value`.", "", "Note: the 'href' setter is already covered by urltestdata.json." ], "protocol": [ { "comment": "The empty string is not a valid scheme. Setter leaves the URL unchanged.", "href": "a://example.net", "new_value": "", "expected": { "href": "a://example.net/", "protocol": "a:" } }, { "href": "a://example.net", "new_value": "b", "expected": { "href": "b://example.net/", "protocol": "b:" } }, { "comment": "Upper-case ASCII is lower-cased", "href": "a://example.net", "new_value": "B", "expected": { "href": "b://example.net/", "protocol": "b:" } }, { "comment": "Non-ASCII is rejected", "href": "a://example.net", "new_value": "é", "expected": { "href": "a://example.net/", "protocol": "a:" } }, { "comment": "No leading digit", "href": "a://example.net", "new_value": "0b", "expected": { "href": "a://example.net/", "protocol": "a:" } }, { "comment": "No leading punctuation", "href": "a://example.net", "new_value": "+b", "expected": { "href": "a://example.net/", "protocol": "a:" } }, { "href": "a://example.net", "new_value": "bC0+-.", "expected": { "href": "bc0+-.://example.net/", "protocol": "bc0+-.:" } }, { "comment": "Only some punctuation is acceptable", "href": "a://example.net", "new_value": "b,c", "expected": { "href": "a://example.net/", "protocol": "a:" } }, { "comment": "Non-ASCII is rejected", "href": "a://example.net", "new_value": "bé", "expected": { "href": "a://example.net/", "protocol": "a:" } }, { "comment": "Can’t switch from special scheme to non-special. Note: this may change, see https://github.com/whatwg/url/issues/104", "href": "http://example.net", "new_value": "b", "expected": { "href": "http://example.net/", "protocol": "http:" } }, { "comment": "Cannot-be-a-base URL doesn’t have a host, but URL in a special scheme must.", "href": "mailto:me@example.net", "new_value": "http", "expected": { "href": "mailto:me@example.net", "protocol": "mailto:" } }, { "comment": "Can’t switch from non-special scheme to special. Note: this may change, see https://github.com/whatwg/url/issues/104", "href": "ssh://me@example.net", "new_value": "http", "expected": { "href": "ssh://me@example.net/", "protocol": "ssh:" } }, { "comment": "Stuff after the first ':' is ignored", "href": "http://example.net", "new_value": "https:foo : bar", "expected": { "href": "https://example.net/", "protocol": "https:" } }, { "comment": "Stuff after the first ':' is ignored", "href": "data:text/html,

Test", "new_value": "view-source+data:foo : bar", "expected": { "href": "view-source+data:text/html,

Test", "protocol": "view-source+data:" } } ], "username": [ { "comment": "No host means no username", "href": "file:///home/you/index.html", "new_value": "me", "expected": { "href": "file:///home/you/index.html", "username": "" } }, { "comment": "No host means no username", "href": "unix:/run/foo.socket", "new_value": "me", "expected": { "href": "unix:/run/foo.socket", "username": "" } }, { "comment": "Cannot-be-a-base means no username", "href": "mailto:you@example.net", "new_value": "me", "expected": { "href": "mailto:you@example.net", "username": "" } }, { "href": "http://example.net", "new_value": "me", "expected": { "href": "http://me@example.net/", "username": "me" } }, { "href": "http://:secret@example.net", "new_value": "me", "expected": { "href": "http://me:secret@example.net/", "username": "me" } }, { "href": "http://me@example.net", "new_value": "", "expected": { "href": "http://example.net/", "username": "" } }, { "href": "http://me:secret@example.net", "new_value": "", "expected": { "href": "http://:secret@example.net/", "username": "" } }, { "comment": "UTF-8 percent encoding with the userinfo encode set.", "href": "http://example.net", "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", "expected": { "href": "http://%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/", "username": "%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9" } }, { "comment": "Bytes already percent-encoded are left as-is.", "href": "http://example.net", "new_value": "%c3%89té", "expected": { "href": "http://%c3%89t%C3%A9@example.net/", "username": "%c3%89t%C3%A9" } } ], "password": [ { "comment": "No host means no password", "href": "file:///home/me/index.html", "new_value": "secret", "expected": { "href": "file:///home/me/index.html", "password": "" } }, { "comment": "No host means no password", "href": "unix:/run/foo.socket", "new_value": "secret", "expected": { "href": "unix:/run/foo.socket", "password": "" } }, { "comment": "Cannot-be-a-base means no password", "href": "mailto:me@example.net", "new_value": "secret", "expected": { "href": "mailto:me@example.net", "password": "" } }, { "href": "http://example.net", "new_value": "secret", "expected": { "href": "http://:secret@example.net/", "password": "secret" } }, { "href": "http://me@example.net", "new_value": "secret", "expected": { "href": "http://me:secret@example.net/", "password": "secret" } }, { "href": "http://:secret@example.net", "new_value": "", "expected": { "href": "http://example.net/", "password": "" } }, { "href": "http://me:secret@example.net", "new_value": "", "expected": { "href": "http://me@example.net/", "password": "" } }, { "comment": "UTF-8 percent encoding with the userinfo encode set.", "href": "http://example.net", "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", "expected": { "href": "http://:%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9@example.net/", "password": "%00%01%09%0A%0D%1F%20!%22%23$%&'()*+,-.%2F09%3A%3B%3C%3D%3E%3F%40AZ%5B%5C%5D%5E_%60az%7B%7C%7D~%7F%C2%80%C2%81%C3%89%C3%A9" } }, { "comment": "Bytes already percent-encoded are left as-is.", "href": "http://example.net", "new_value": "%c3%89té", "expected": { "href": "http://:%c3%89t%C3%A9@example.net/", "password": "%c3%89t%C3%A9" } } ], "host": [ { "comment": "Cannot-be-a-base means no host", "href": "mailto:me@example.net", "new_value": "example.com", "expected": { "href": "mailto:me@example.net", "host": "" } }, { "comment": "Cannot-be-a-base means no password", "href": "data:text/plain,Stuff", "new_value": "example.net", "expected": { "href": "data:text/plain,Stuff", "host": "" } }, { "href": "http://example.net", "new_value": "example.com:8080", "expected": { "href": "http://example.com:8080/", "host": "example.com:8080", "hostname": "example.com", "port": "8080" } }, { "comment": "Port number is unchanged if not specified in the new value", "href": "http://example.net:8080", "new_value": "example.com", "expected": { "href": "http://example.com:8080/", "host": "example.com:8080", "hostname": "example.com", "port": "8080" } }, { "comment": "Port number is unchanges if empty in the new value. Note: this may change, see https://github.com/whatwg/url/pull/113", "href": "http://example.net:8080", "new_value": "example.com:", "expected": { "href": "http://example.com:8080/", "host": "example.com:8080", "hostname": "example.com", "port": "8080" } }, { "comment": "The empty host is not valid for special schemes", "href": "http://example.net", "new_value": "", "expected": { "href": "http://example.net/", "host": "example.net" } }, { "comment": "The empty host is OK for non-special schemes", "href": "view-source+http://example.net/foo", "new_value": "", "expected": { "href": "view-source+http:///foo", "host": "" } }, { "comment": "Path-only URLs can gain a host", "href": "a:/foo", "new_value": "example.net", "expected": { "href": "a://example.net/foo", "host": "example.net" } }, { "comment": "IPv4 address syntax is normalized", "href": "http://example.net", "new_value": "0x7F000001:8080", "expected": { "href": "http://127.0.0.1:8080/", "host": "127.0.0.1:8080", "hostname": "127.0.0.1", "port": "8080" } }, { "comment": "IPv6 address syntax is normalized", "href": "http://example.net", "new_value": "[::0:01]:2", "expected": { "href": "http://[::1]:2/", "host": "[::1]:2", "hostname": "[::1]", "port": "2" } }, { "comment": "Default port number is removed", "href": "http://example.net", "new_value": "example.com:80", "expected": { "href": "http://example.com/", "host": "example.com", "hostname": "example.com", "port": "" } }, { "comment": "Default port number is removed", "href": "https://example.net", "new_value": "example.com:443", "expected": { "href": "https://example.com/", "host": "example.com", "hostname": "example.com", "port": "" } }, { "comment": "Default port number is only removed for the relevant scheme", "href": "https://example.net", "new_value": "example.com:80", "expected": { "href": "https://example.com:80/", "host": "example.com:80", "hostname": "example.com", "port": "80" } }, { "comment": "Stuff after a / delimiter is ignored", "href": "http://example.net/path", "new_value": "example.com/stuff", "expected": { "href": "http://example.com/path", "host": "example.com", "hostname": "example.com", "port": "" } }, { "comment": "Stuff after a / delimiter is ignored", "href": "http://example.net/path", "new_value": "example.com:8080/stuff", "expected": { "href": "http://example.com:8080/path", "host": "example.com:8080", "hostname": "example.com", "port": "8080" } }, { "comment": "Stuff after a ? delimiter is ignored", "href": "http://example.net/path", "new_value": "example.com?stuff", "expected": { "href": "http://example.com/path", "host": "example.com", "hostname": "example.com", "port": "" } }, { "comment": "Stuff after a ? delimiter is ignored", "href": "http://example.net/path", "new_value": "example.com:8080?stuff", "expected": { "href": "http://example.com:8080/path", "host": "example.com:8080", "hostname": "example.com", "port": "8080" } }, { "comment": "Stuff after a # delimiter is ignored", "href": "http://example.net/path", "new_value": "example.com#stuff", "expected": { "href": "http://example.com/path", "host": "example.com", "hostname": "example.com", "port": "" } }, { "comment": "Stuff after a # delimiter is ignored", "href": "http://example.net/path", "new_value": "example.com:8080#stuff", "expected": { "href": "http://example.com:8080/path", "host": "example.com:8080", "hostname": "example.com", "port": "8080" } }, { "comment": "Stuff after a \\ delimiter is ignored for special schemes", "href": "http://example.net/path", "new_value": "example.com\\stuff", "expected": { "href": "http://example.com/path", "host": "example.com", "hostname": "example.com", "port": "" } }, { "comment": "Stuff after a \\ delimiter is ignored for special schemes", "href": "http://example.net/path", "new_value": "example.com:8080\\stuff", "expected": { "href": "http://example.com:8080/path", "host": "example.com:8080", "hostname": "example.com", "port": "8080" } }, { "comment": "\\ is not a delimiter for non-special schemes, and it’s invalid in a domain", "href": "view-source+http://example.net/path", "new_value": "example.com\\stuff", "expected": { "href": "view-source+http://example.net/path", "host": "example.net", "hostname": "example.net", "port": "" } }, { "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", "href": "view-source+http://example.net/path", "new_value": "example.com:8080stuff2", "expected": { "href": "view-source+http://example.com:8080/path", "host": "example.com:8080", "hostname": "example.com", "port": "8080" } }, { "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", "href": "http://example.net/path", "new_value": "example.com:8080stuff2", "expected": { "href": "http://example.com:8080/path", "host": "example.com:8080", "hostname": "example.com", "port": "8080" } }, { "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", "href": "http://example.net/path", "new_value": "example.com:8080+2", "expected": { "href": "http://example.com:8080/path", "host": "example.com:8080", "hostname": "example.com", "port": "8080" } }, { "comment": "Port numbers are 16 bit integers", "href": "http://example.net/path", "new_value": "example.com:65535", "expected": { "href": "http://example.com:65535/path", "host": "example.com:65535", "hostname": "example.com", "port": "65535" } }, { "comment": "Port numbers are 16 bit integers, overflowing is an error. Hostname is still set, though.", "href": "http://example.net/path", "new_value": "example.com:65536", "expected": { "href": "http://example.com/path", "host": "example.com", "hostname": "example.com", "port": "" } } ], "hostname": [ { "comment": "Cannot-be-a-base means no host", "href": "mailto:me@example.net", "new_value": "example.com", "expected": { "href": "mailto:me@example.net", "host": "" } }, { "comment": "Cannot-be-a-base means no password", "href": "data:text/plain,Stuff", "new_value": "example.net", "expected": { "href": "data:text/plain,Stuff", "host": "" } }, { "href": "http://example.net:8080", "new_value": "example.com", "expected": { "href": "http://example.com:8080/", "host": "example.com:8080", "hostname": "example.com", "port": "8080" } }, { "comment": "The empty host is not valid for special schemes", "href": "http://example.net", "new_value": "", "expected": { "href": "http://example.net/", "host": "example.net" } }, { "comment": "The empty host is OK for non-special schemes", "href": "view-source+http://example.net/foo", "new_value": "", "expected": { "href": "view-source+http:///foo", "host": "" } }, { "comment": "Path-only URLs can gain a host", "href": "a:/foo", "new_value": "example.net", "expected": { "href": "a://example.net/foo", "host": "example.net" } }, { "comment": "IPv4 address syntax is normalized", "href": "http://example.net:8080", "new_value": "0x7F000001", "expected": { "href": "http://127.0.0.1:8080/", "host": "127.0.0.1:8080", "hostname": "127.0.0.1", "port": "8080" } }, { "comment": "IPv6 address syntax is normalized", "href": "http://example.net", "new_value": "[::0:01]", "expected": { "href": "http://[::1]/", "host": "[::1]", "hostname": "[::1]", "port": "" } }, { "comment": "Stuff after a : delimiter is ignored", "href": "http://example.net/path", "new_value": "example.com:8080", "expected": { "href": "http://example.com/path", "host": "example.com", "hostname": "example.com", "port": "" } }, { "comment": "Stuff after a : delimiter is ignored", "href": "http://example.net:8080/path", "new_value": "example.com:", "expected": { "href": "http://example.com:8080/path", "host": "example.com:8080", "hostname": "example.com", "port": "8080" } }, { "comment": "Stuff after a / delimiter is ignored", "href": "http://example.net/path", "new_value": "example.com/stuff", "expected": { "href": "http://example.com/path", "host": "example.com", "hostname": "example.com", "port": "" } }, { "comment": "Stuff after a ? delimiter is ignored", "href": "http://example.net/path", "new_value": "example.com?stuff", "expected": { "href": "http://example.com/path", "host": "example.com", "hostname": "example.com", "port": "" } }, { "comment": "Stuff after a # delimiter is ignored", "href": "http://example.net/path", "new_value": "example.com#stuff", "expected": { "href": "http://example.com/path", "host": "example.com", "hostname": "example.com", "port": "" } }, { "comment": "Stuff after a \\ delimiter is ignored for special schemes", "href": "http://example.net/path", "new_value": "example.com\\stuff", "expected": { "href": "http://example.com/path", "host": "example.com", "hostname": "example.com", "port": "" } }, { "comment": "\\ is not a delimiter for non-special schemes, and it’s invalid in a domain", "href": "view-source+http://example.net/path", "new_value": "example.com\\stuff", "expected": { "href": "view-source+http://example.net/path", "host": "example.net", "hostname": "example.net", "port": "" } } ], "port": [ { "href": "http://example.net", "new_value": "8080", "expected": { "href": "http://example.net:8080/", "host": "example.net:8080", "hostname": "example.net", "port": "8080" } }, { "comment": "Port number is unchanged if empty in the new value. Note: this may change, see https://github.com/whatwg/url/pull/113", "href": "http://example.net:8080", "new_value": "", "expected": { "href": "http://example.net:8080/", "host": "example.net:8080", "hostname": "example.net", "port": "8080" } }, { "comment": "Default port number is removed", "href": "http://example.net:8080", "new_value": "80", "expected": { "href": "http://example.net/", "host": "example.net", "hostname": "example.net", "port": "" } }, { "comment": "Default port number is removed", "href": "https://example.net:4433", "new_value": "443", "expected": { "href": "https://example.net/", "host": "example.net", "hostname": "example.net", "port": "" } }, { "comment": "Default port number is only removed for the relevant scheme", "href": "https://example.net", "new_value": "80", "expected": { "href": "https://example.net:80/", "host": "example.net:80", "hostname": "example.net", "port": "80" } }, { "comment": "Stuff after a / delimiter is ignored", "href": "http://example.net/path", "new_value": "8080/stuff", "expected": { "href": "http://example.net:8080/path", "host": "example.net:8080", "hostname": "example.net", "port": "8080" } }, { "comment": "Stuff after a ? delimiter is ignored", "href": "http://example.net/path", "new_value": "8080?stuff", "expected": { "href": "http://example.net:8080/path", "host": "example.net:8080", "hostname": "example.net", "port": "8080" } }, { "comment": "Stuff after a # delimiter is ignored", "href": "http://example.net/path", "new_value": "8080#stuff", "expected": { "href": "http://example.net:8080/path", "host": "example.net:8080", "hostname": "example.net", "port": "8080" } }, { "comment": "Stuff after a \\ delimiter is ignored for special schemes", "href": "http://example.net/path", "new_value": "8080\\stuff", "expected": { "href": "http://example.net:8080/path", "host": "example.net:8080", "hostname": "example.net", "port": "8080" } }, { "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", "href": "view-source+http://example.net/path", "new_value": "8080stuff2", "expected": { "href": "view-source+http://example.net:8080/path", "host": "example.net:8080", "hostname": "example.net", "port": "8080" } }, { "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", "href": "http://example.net/path", "new_value": "8080stuff2", "expected": { "href": "http://example.net:8080/path", "host": "example.net:8080", "hostname": "example.net", "port": "8080" } }, { "comment": "Anything other than ASCII digit stops the port parser in a setter but is not an error", "href": "http://example.net/path", "new_value": "8080+2", "expected": { "href": "http://example.net:8080/path", "host": "example.net:8080", "hostname": "example.net", "port": "8080" } }, { "comment": "Port numbers are 16 bit integers", "href": "http://example.net/path", "new_value": "65535", "expected": { "href": "http://example.net:65535/path", "host": "example.net:65535", "hostname": "example.net", "port": "65535" } }, { "comment": "Port numbers are 16 bit integers, overflowing is an error", "href": "http://example.net:8080/path", "new_value": "65536", "expected": { "href": "http://example.net:8080/path", "host": "example.net:8080", "hostname": "example.net", "port": "8080" } } ], "pathname": [ { "comment": "Cannot-be-a-base don’t have a path", "href": "mailto:me@example.net", "new_value": "/foo", "expected": { "href": "mailto:me@example.net", "pathname": "me@example.net" } }, { "href": "unix:/run/foo.socket?timeout=10", "new_value": "/var/log/../run/bar.socket", "expected": { "href": "unix:/var/run/bar.socket?timeout=10", "pathname": "/var/run/bar.socket" } }, { "href": "https://example.net#nav", "new_value": "home", "expected": { "href": "https://example.net/home#nav", "pathname": "/home" } }, { "href": "https://example.net#nav", "new_value": "../home", "expected": { "href": "https://example.net/home#nav", "pathname": "/home" } }, { "comment": "\\ is a segment delimiter for 'special' URLs", "href": "http://example.net/home?lang=fr#nav", "new_value": "\\a\\%2E\\b\\%2e.\\c", "expected": { "href": "http://example.net/a/c?lang=fr#nav", "pathname": "/a/c" } }, { "comment": "\\ is *not* a segment delimiter for non-'special' URLs", "href": "view-source+http://example.net/home?lang=fr#nav", "new_value": "\\a\\%2E\\b\\%2e.\\c", "expected": { "href": "view-source+http://example.net/\\a\\.\\b\\..\\c?lang=fr#nav", "pathname": "/\\a\\.\\b\\..\\c" } }, { "comment": "UTF-8 percent encoding with the default encode set. Tabs and newlines are removed.", "href": "a:/", "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", "expected": { "href": "a:/%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E%3F@AZ[\\]^_%60az%7B|%7D~%7F%C2%80%C2%81%C3%89%C3%A9", "pathname": "/%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E%3F@AZ[\\]^_%60az%7B|%7D~%7F%C2%80%C2%81%C3%89%C3%A9" } }, { "comment": "Bytes already percent-encoded are left as-is, except %2E.", "href": "http://example.net", "new_value": "%2e%2E%c3%89té", "expected": { "href": "http://example.net/..%c3%89t%C3%A9", "pathname": "/..%c3%89t%C3%A9" } } ], "search": [ { "href": "https://example.net#nav", "new_value": "lang=fr", "expected": { "href": "https://example.net/?lang=fr#nav", "search": "?lang=fr" } }, { "href": "https://example.net?lang=en-US#nav", "new_value": "lang=fr", "expected": { "href": "https://example.net/?lang=fr#nav", "search": "?lang=fr" } }, { "href": "https://example.net?lang=en-US#nav", "new_value": "?lang=fr", "expected": { "href": "https://example.net/?lang=fr#nav", "search": "?lang=fr" } }, { "href": "https://example.net?lang=en-US#nav", "new_value": "??lang=fr", "expected": { "href": "https://example.net/??lang=fr#nav", "search": "??lang=fr" } }, { "href": "https://example.net?lang=en-US#nav", "new_value": "?", "expected": { "href": "https://example.net/?#nav", "search": "" } }, { "href": "https://example.net?lang=en-US#nav", "new_value": "", "expected": { "href": "https://example.net/#nav", "search": "" } }, { "href": "https://example.net?lang=en-US", "new_value": "", "expected": { "href": "https://example.net/", "search": "" } }, { "href": "https://example.net", "new_value": "", "expected": { "href": "https://example.net/", "search": "" } }, { "comment": "UTF-8 percent encoding with the query encode set. Tabs and newlines are removed.", "href": "a:/", "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", "expected": { "href": "a:/?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9", "search": "?%00%01%1F%20!%22%23$%&'()*+,-./09:;%3C=%3E?@AZ[\\]^_`az{|}~%7F%C2%80%C2%81%C3%89%C3%A9" } }, { "comment": "Bytes already percent-encoded are left as-is", "href": "http://example.net", "new_value": "%c3%89té", "expected": { "href": "http://example.net/?%c3%89t%C3%A9", "search": "?%c3%89t%C3%A9" } } ], "hash": [ { "href": "https://example.net", "new_value": "main", "expected": { "href": "https://example.net/#main", "hash": "#main" } }, { "href": "https://example.net#nav", "new_value": "main", "expected": { "href": "https://example.net/#main", "hash": "#main" } }, { "href": "https://example.net?lang=en-US", "new_value": "##nav", "expected": { "href": "https://example.net/?lang=en-US##nav", "hash": "##nav" } }, { "href": "https://example.net?lang=en-US#nav", "new_value": "#main", "expected": { "href": "https://example.net/?lang=en-US#main", "hash": "#main" } }, { "href": "https://example.net?lang=en-US#nav", "new_value": "#", "expected": { "href": "https://example.net/?lang=en-US#", "hash": "" } }, { "href": "https://example.net?lang=en-US#nav", "new_value": "", "expected": { "href": "https://example.net/?lang=en-US", "hash": "" } }, { "comment": "No percent-encoding at all (!); nuls, tabs, and newlines are removed", "href": "a:/", "new_value": "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", "expected": { "href": "a:/#\u0001\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé", "hash": "#\u0001\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007f\u0080\u0081Éé" } }, { "comment": "Bytes already percent-encoded are left as-is", "href": "http://example.net", "new_value": "%c3%89té", "expected": { "href": "http://example.net/#%c3%89té", "hash": "#%c3%89té" } } ] }