".into());
+ assert_eq!(open_elements(&parser.tokenizer.sink), ["html", "li", "p"]);
+}
+
+#[test]
+fn text_insertion_mode() {
+ for name in [
+ "iframe", "noembed", "noframes", "noscript", "script", "style", "textarea", "title", "xmp",
+ ] {
+ let mut parser = driver::parse_document(RcDom::default(), ParseOpts::default());
+ parser.process("
".into());
+ assert!(!parser.tokenizer.sink.is_in_text_insertion_mode());
+
+ parser.process(format!("<{name}>").into());
+ assert!(parser.tokenizer.sink.is_in_text_insertion_mode(), "{name}");
+ assert_eq!(
+ open_elements(&parser.tokenizer.sink),
+ ["html", "body", name]
+ );
+
+ // Character tokens are inserted into the current node, which is that element.
+ parser.process("".into());
+ assert!(parser.tokenizer.sink.is_in_text_insertion_mode(), "{name}");
+ assert_eq!(current_node_text(&parser.tokenizer.sink), "
", "{name}");
+
+ parser.process(format!("{name}>").into());
+ assert!(!parser.tokenizer.sink.is_in_text_insertion_mode(), "{name}");
+ assert_eq!(open_elements(&parser.tokenizer.sink), ["html", "body"]);
+ }
+}
+
+#[test]
+fn text_insertion_mode_ends_at_eof() {
+ let mut parser = driver::parse_document(RcDom::default(), ParseOpts::default());
+ parser.process("