diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/Document-createProcessingInstruction-xhtml.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/Document-createProcessingInstruction-xhtml.txt
new file mode 100644
index 00000000000..5c18a38fa32
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/Document-createProcessingInstruction-xhtml.txt
@@ -0,0 +1,22 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 12 tests
+
+12 Pass
+Details
+Result Test Name MessagePass Document.createProcessingInstruction in XML documents
+Pass Should throw an INVALID_CHARACTER_ERR for target "A" and data "?>".
+Pass Should throw an INVALID_CHARACTER_ERR for target "·A" and data "x".
+Pass Should throw an INVALID_CHARACTER_ERR for target "×A" and data "x".
+Pass Should throw an INVALID_CHARACTER_ERR for target "A×" and data "x".
+Pass Should throw an INVALID_CHARACTER_ERR for target "\\A" and data "x".
+Pass Should throw an INVALID_CHARACTER_ERR for target "\f" and data "x".
+Pass Should throw an INVALID_CHARACTER_ERR for target 0 and data "x".
+Pass Should throw an INVALID_CHARACTER_ERR for target "0" and data "x".
+Pass Should get a ProcessingInstruction for target "xml:fail" and data "x".
+Pass Should get a ProcessingInstruction for target "A·A" and data "x".
+Pass Should get a ProcessingInstruction for target "a0" and data "x".
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/Document-createProcessingInstruction.txt b/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/Document-createProcessingInstruction.txt
new file mode 100644
index 00000000000..257ee6d1929
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/wpt-import/dom/nodes/Document-createProcessingInstruction.txt
@@ -0,0 +1,22 @@
+Summary
+
+Harness status: OK
+
+Rerun
+
+Found 12 tests
+
+12 Pass
+Details
+Result Test Name MessagePass Document.createProcessingInstruction in HTML documents
+Pass Should throw an INVALID_CHARACTER_ERR for target "A" and data "?>".
+Pass Should throw an INVALID_CHARACTER_ERR for target "·A" and data "x".
+Pass Should throw an INVALID_CHARACTER_ERR for target "×A" and data "x".
+Pass Should throw an INVALID_CHARACTER_ERR for target "A×" and data "x".
+Pass Should throw an INVALID_CHARACTER_ERR for target "\\A" and data "x".
+Pass Should throw an INVALID_CHARACTER_ERR for target "\f" and data "x".
+Pass Should throw an INVALID_CHARACTER_ERR for target 0 and data "x".
+Pass Should throw an INVALID_CHARACTER_ERR for target "0" and data "x".
+Pass Should get a ProcessingInstruction for target "xml:fail" and data "x".
+Pass Should get a ProcessingInstruction for target "A·A" and data "x".
+Pass Should get a ProcessingInstruction for target "a0" and data "x".
\ No newline at end of file
diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/nodes/Document-createProcessingInstruction-xhtml.xhtml b/Tests/LibWeb/Text/input/wpt-import/dom/nodes/Document-createProcessingInstruction-xhtml.xhtml
new file mode 100644
index 00000000000..287be72601d
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/dom/nodes/Document-createProcessingInstruction-xhtml.xhtml
@@ -0,0 +1,15 @@
+
+
+Document.createProcessingInstruction in XML documents
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/nodes/Document-createProcessingInstruction.html b/Tests/LibWeb/Text/input/wpt-import/dom/nodes/Document-createProcessingInstruction.html
new file mode 100644
index 00000000000..00d69c93319
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/dom/nodes/Document-createProcessingInstruction.html
@@ -0,0 +1,11 @@
+
+
+Document.createProcessingInstruction in HTML documents
+
+
+
+
+
+
+
+
diff --git a/Tests/LibWeb/Text/input/wpt-import/dom/nodes/Document-createProcessingInstruction.js b/Tests/LibWeb/Text/input/wpt-import/dom/nodes/Document-createProcessingInstruction.js
new file mode 100644
index 00000000000..d6cc3725f03
--- /dev/null
+++ b/Tests/LibWeb/Text/input/wpt-import/dom/nodes/Document-createProcessingInstruction.js
@@ -0,0 +1,39 @@
+test(function() {
+ var invalid = [
+ ["A", "?>"],
+ ["\u00B7A", "x"],
+ ["\u00D7A", "x"],
+ ["A\u00D7", "x"],
+ ["\\A", "x"],
+ ["\f", "x"],
+ [0, "x"],
+ ["0", "x"]
+ ],
+ valid = [
+ ["xml:fail", "x"],
+ ["A\u00B7A", "x"],
+ ["a0", "x"]
+ ]
+
+ for (var i = 0, il = invalid.length; i < il; i++) {
+ test(function() {
+ assert_throws_dom("INVALID_CHARACTER_ERR", function() {
+ document.createProcessingInstruction(invalid[i][0], invalid[i][1])
+ })
+ }, "Should throw an INVALID_CHARACTER_ERR for target " +
+ format_value(invalid[i][0]) + " and data " +
+ format_value(invalid[i][1]) + ".")
+ }
+ for (var i = 0, il = valid.length; i < il; ++i) {
+ test(function() {
+ var pi = document.createProcessingInstruction(valid[i][0], valid[i][1]);
+ assert_equals(pi.target, valid[i][0]);
+ assert_equals(pi.data, valid[i][1]);
+ assert_equals(pi.ownerDocument, document);
+ assert_true(pi instanceof ProcessingInstruction);
+ assert_true(pi instanceof Node);
+ }, "Should get a ProcessingInstruction for target " +
+ format_value(valid[i][0]) + " and data " +
+ format_value(valid[i][1]) + ".")
+ }
+})
diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp
index b0749e76c9e..d7bbc97bb46 100644
--- a/Userland/Libraries/LibWeb/DOM/Document.cpp
+++ b/Userland/Libraries/LibWeb/DOM/Document.cpp
@@ -1740,9 +1740,13 @@ JS::NonnullGCPtr Document::create_comment(String const& data)
// https://dom.spec.whatwg.org/#dom-document-createprocessinginstruction
WebIDL::ExceptionOr> Document::create_processing_instruction(String const& target, String const& data)
{
- // FIXME: 1. If target does not match the Name production, then throw an "InvalidCharacterError" DOMException.
+ // 1. If target does not match the Name production, then throw an "InvalidCharacterError" DOMException.
+ if (!is_valid_name(target))
+ return WebIDL::InvalidCharacterError::create(realm(), "Invalid character in target name."_string);
- // FIXME: 2. If data contains the string "?>", then throw an "InvalidCharacterError" DOMException.
+ // 2. If data contains the string "?>", then throw an "InvalidCharacterError" DOMException.
+ if (data.contains("?>"sv))
+ return WebIDL::InvalidCharacterError::create(realm(), "String may not contain '?>'"_string);
// 3. Return a new ProcessingInstruction node, with target set to target, data set to data, and node document set to this.
return heap().allocate(realm(), *this, data, target);