• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.jsoup.nodes;
2 
3 import org.jsoup.Jsoup;
4 import org.jsoup.TextUtil;
5 import org.jsoup.integration.ParseTest;
6 import org.jsoup.nodes.Document.OutputSettings;
7 import org.jsoup.nodes.Document.OutputSettings.Syntax;
8 import org.jsoup.parser.ParseSettings;
9 import org.jsoup.parser.Parser;
10 import org.jsoup.select.Elements;
11 import org.junit.jupiter.api.Disabled;
12 import org.junit.jupiter.api.Test;
13 
14 import java.io.*;
15 import java.nio.charset.Charset;
16 import java.nio.charset.StandardCharsets;
17 import java.util.List;
18 
19 import static org.junit.jupiter.api.Assertions.*;
20 
21 /**
22  Tests for Document.
23 
24  @author Jonathan Hedley, jonathan@hedley.net */
25 public class DocumentTest {
26     private static final String charsetUtf8 = "UTF-8";
27     private static final String charsetIso8859 = "ISO-8859-1";
28 
29 
setTextPreservesDocumentStructure()30     @Test public void setTextPreservesDocumentStructure() {
31         Document doc = Jsoup.parse("<p>Hello</p>");
32         doc.text("Replaced");
33         assertEquals("Replaced", doc.text());
34         assertEquals("Replaced", doc.body().text());
35         assertEquals(1, doc.select("head").size());
36     }
37 
testTitles()38     @Test public void testTitles() {
39         Document noTitle = Jsoup.parse("<p>Hello</p>");
40         Document withTitle = Jsoup.parse("<title>First</title><title>Ignore</title><p>Hello</p>");
41 
42         assertEquals("", noTitle.title());
43         noTitle.title("Hello");
44         assertEquals("Hello", noTitle.title());
45         assertEquals("Hello", noTitle.select("title").first().text());
46 
47         assertEquals("First", withTitle.title());
48         withTitle.title("Hello");
49         assertEquals("Hello", withTitle.title());
50         assertEquals("Hello", withTitle.select("title").first().text());
51 
52         Document normaliseTitle = Jsoup.parse("<title>   Hello\nthere   \n   now   \n");
53         assertEquals("Hello there now", normaliseTitle.title());
54     }
55 
testOutputEncoding()56     @Test public void testOutputEncoding() {
57         Document doc = Jsoup.parse("<p title=π>π & < > </p>");
58         // default is utf-8
59         assertEquals("<p title=\"π\">π &amp; &lt; &gt;</p>", doc.body().html());
60         assertEquals("UTF-8", doc.outputSettings().charset().name());
61 
62         doc.outputSettings().charset("ascii");
63         assertEquals(Entities.EscapeMode.base, doc.outputSettings().escapeMode());
64         assertEquals("<p title=\"&#x3c0;\">&#x3c0; &amp; &lt; &gt;</p>", doc.body().html());
65 
66         doc.outputSettings().escapeMode(Entities.EscapeMode.extended);
67         assertEquals("<p title=\"&pi;\">&pi; &amp; &lt; &gt;</p>", doc.body().html());
68     }
69 
testXhtmlReferences()70     @Test public void testXhtmlReferences() {
71         Document doc = Jsoup.parse("&lt; &gt; &amp; &quot; &apos; &times;");
72         doc.outputSettings().escapeMode(Entities.EscapeMode.xhtml);
73         assertEquals("&lt; &gt; &amp; \" ' ×", doc.body().html());
74     }
75 
testNormalisesStructure()76     @Test public void testNormalisesStructure() {
77         Document doc = Jsoup.parse("<html><head><script>one</script><noscript><p>two</p></noscript></head><body><p>three</p></body><p>four</p></html>");
78         assertEquals("<html><head><script>one</script><noscript>&lt;p&gt;two</noscript></head><body><p>three</p><p>four</p></body></html>", TextUtil.stripNewlines(doc.html()));
79     }
80 
accessorsWillNormalizeStructure()81     @Test public void accessorsWillNormalizeStructure() {
82         Document doc = new Document("");
83         assertEquals("", doc.html());
84 
85         Element body = doc.body();
86         assertEquals("body", body.tagName());
87         Element head = doc.head();
88         assertEquals("head", head.tagName());
89         assertEquals("<html><head></head><body></body></html>", TextUtil.stripNewlines(doc.html()));
90     }
91 
accessorsAreCaseInsensitive()92     @Test public void accessorsAreCaseInsensitive() {
93         Parser parser = Parser.htmlParser().settings(ParseSettings.preserveCase);
94         Document doc = parser.parseInput("<!DOCTYPE html><HTML><HEAD><TITLE>SHOUTY</TITLE></HEAD><BODY>HELLO</BODY></HTML>", "");
95 
96         Element body = doc.body();
97         assertEquals("BODY", body.tagName());
98         assertEquals("body", body.normalName());
99         Element head = doc.head();
100         assertEquals("HEAD", head.tagName());
101         assertEquals("body", body.normalName());
102 
103         Element root = doc.selectFirst("html");
104         assertEquals("HTML", root.tagName());
105         assertEquals("html", root.normalName());
106         assertEquals("SHOUTY", doc.title());
107     }
108 
testClone()109     @Test public void testClone() {
110         Document doc = Jsoup.parse("<title>Hello</title> <p>One<p>Two");
111         Document clone = doc.clone();
112 
113         assertEquals("<html><head><title>Hello</title></head><body><p>One</p><p>Two</p></body></html>", TextUtil.stripNewlines(clone.html()));
114         clone.title("Hello there");
115         clone.expectFirst("p").text("One more").attr("id", "1");
116         assertEquals("<html><head><title>Hello there</title></head><body><p id=\"1\">One more</p><p>Two</p></body></html>", TextUtil.stripNewlines(clone.html()));
117         assertEquals("<html><head><title>Hello</title></head><body><p>One</p><p>Two</p></body></html>", TextUtil.stripNewlines(doc.html()));
118     }
119 
testBasicIndent()120     @Test void testBasicIndent() {
121         Document doc = Jsoup.parse("<title>Hello</title> <p>One<p>Two");
122         String expect = "<html>\n <head>\n  <title>Hello</title>\n </head>\n <body>\n  <p>One</p>\n  <p>Two</p>\n </body>\n</html>";
123         assertEquals(expect, doc.html());
124     }
125 
testClonesDeclarations()126     @Test public void testClonesDeclarations() {
127         Document doc = Jsoup.parse("<!DOCTYPE html><html><head><title>Doctype test");
128         Document clone = doc.clone();
129 
130         assertEquals(doc.html(), clone.html());
131         assertEquals("<!doctype html><html><head><title>Doctype test</title></head><body></body></html>",
132                 TextUtil.stripNewlines(clone.html()));
133     }
134 
testLocation()135     @Test public void testLocation() throws IOException {
136         // tests location vs base href
137         File in = ParseTest.getFile("/htmltests/basehref.html");
138         Document doc = Jsoup.parse(in, "UTF-8", "http://example.com/");
139         String location = doc.location();
140         String baseUri = doc.baseUri();
141         assertEquals("http://example.com/", location);
142         assertEquals("https://example.com/path/file.html?query", baseUri);
143         assertEquals("./anotherfile.html", doc.expectFirst("a").attr("href"));
144         assertEquals("https://example.com/path/anotherfile.html", doc.expectFirst("a").attr("abs:href"));
145     }
146 
testLocationFromString()147     @Test public void testLocationFromString() {
148         Document doc = Jsoup.parse("<p>Hello");
149         assertEquals("", doc.location());
150     }
151 
testHtmlAndXmlSyntax()152     @Test public void testHtmlAndXmlSyntax() {
153         String h = "<!DOCTYPE html><body><img async checked='checked' src='&<>\"'>&lt;&gt;&amp;&quot;<foo />bar";
154         Document doc = Jsoup.parse(h);
155 
156         doc.outputSettings().syntax(Syntax.html);
157         assertEquals("<!doctype html>\n" +
158                 "<html>\n" +
159                 " <head></head>\n" +
160                 " <body>\n" +
161                 "  <img async checked src=\"&amp;<>&quot;\">&lt;&gt;&amp;\"<foo />bar\n" +
162                 " </body>\n" +
163                 "</html>", doc.html());
164 
165         doc.outputSettings().syntax(Document.OutputSettings.Syntax.xml);
166         assertEquals("<!DOCTYPE html>\n" +
167                 "<html>\n" +
168                 " <head></head>\n" +
169                 " <body>\n" +
170                 "  <img async=\"\" checked=\"checked\" src=\"&amp;&lt;>&quot;\" />&lt;&gt;&amp;\"<foo />bar\n" +
171                 " </body>\n" +
172                 "</html>", doc.html());
173     }
174 
htmlParseDefaultsToHtmlOutputSyntax()175     @Test public void htmlParseDefaultsToHtmlOutputSyntax() {
176         Document doc = Jsoup.parse("x");
177         assertEquals(Syntax.html, doc.outputSettings().syntax());
178     }
179 
testHtmlAppendable()180     @Test public void testHtmlAppendable() {
181     	String htmlContent = "<html><head><title>Hello</title></head><body><p>One</p><p>Two</p></body></html>";
182     	Document document = Jsoup.parse(htmlContent);
183     	OutputSettings outputSettings = new OutputSettings();
184 
185     	outputSettings.prettyPrint(false);
186     	document.outputSettings(outputSettings);
187     	assertEquals(htmlContent, document.html(new StringWriter()).toString());
188     }
189 
testOverflowClone()190     @Test public void testOverflowClone() {
191         StringBuilder sb = new StringBuilder();
192         sb.append("<head><base href='https://jsoup.org/'>");
193         for (int i = 0; i < 100000; i++) {
194             sb.append("<div>");
195         }
196         sb.append("<p>Hello <a href='/example.html'>there</a>");
197 
198         Document doc = Jsoup.parse(sb.toString());
199 
200         String expectedLink = "https://jsoup.org/example.html";
201         assertEquals(expectedLink, doc.selectFirst("a").attr("abs:href"));
202         Document clone = doc.clone();
203         doc.hasSameValue(clone);
204         assertEquals(expectedLink, clone.selectFirst("a").attr("abs:href"));
205     }
206 
DocumentsWithSameContentAreEqual()207     @Test public void DocumentsWithSameContentAreEqual() {
208         Document docA = Jsoup.parse("<div/>One");
209         Document docB = Jsoup.parse("<div/>One");
210         Document docC = Jsoup.parse("<div/>Two");
211 
212         assertNotEquals(docA, docB);
213         assertEquals(docA, docA);
214         assertEquals(docA.hashCode(), docA.hashCode());
215         assertNotEquals(docA.hashCode(), docC.hashCode());
216     }
217 
DocumentsWithSameContentAreVerifiable()218     @Test public void DocumentsWithSameContentAreVerifiable() {
219         Document docA = Jsoup.parse("<div/>One");
220         Document docB = Jsoup.parse("<div/>One");
221         Document docC = Jsoup.parse("<div/>Two");
222 
223         assertTrue(docA.hasSameValue(docB));
224         assertFalse(docA.hasSameValue(docC));
225     }
226 
227     @Test
testMetaCharsetUpdateUtf8()228     public void testMetaCharsetUpdateUtf8() {
229         final Document doc = createHtmlDocument("changeThis");
230         doc.updateMetaCharsetElement(true);
231         doc.charset(Charset.forName(charsetUtf8));
232 
233         final String htmlCharsetUTF8 = "<html>\n" +
234                                         " <head>\n" +
235                                         "  <meta charset=\"" + charsetUtf8 + "\">\n" +
236                                         " </head>\n" +
237                                         " <body></body>\n" +
238                                         "</html>";
239         assertEquals(htmlCharsetUTF8, doc.toString());
240 
241         Element selectedElement = doc.select("meta[charset]").first();
242         assertEquals(charsetUtf8, doc.charset().name());
243         assertEquals(charsetUtf8, selectedElement.attr("charset"));
244         assertEquals(doc.charset(), doc.outputSettings().charset());
245     }
246 
247     @Test
testMetaCharsetUpdateIso8859()248     public void testMetaCharsetUpdateIso8859() {
249         final Document doc = createHtmlDocument("changeThis");
250         doc.updateMetaCharsetElement(true);
251         doc.charset(Charset.forName(charsetIso8859));
252 
253         final String htmlCharsetISO = "<html>\n" +
254                                         " <head>\n" +
255                                         "  <meta charset=\"" + charsetIso8859 + "\">\n" +
256                                         " </head>\n" +
257                                         " <body></body>\n" +
258                                         "</html>";
259         assertEquals(htmlCharsetISO, doc.toString());
260 
261         Element selectedElement = doc.select("meta[charset]").first();
262         assertEquals(charsetIso8859, doc.charset().name());
263         assertEquals(charsetIso8859, selectedElement.attr("charset"));
264         assertEquals(doc.charset(), doc.outputSettings().charset());
265     }
266 
267     @Test
testMetaCharsetUpdateNoCharset()268     public void testMetaCharsetUpdateNoCharset() {
269         final Document docNoCharset = Document.createShell("");
270         docNoCharset.updateMetaCharsetElement(true);
271         docNoCharset.charset(Charset.forName(charsetUtf8));
272 
273         assertEquals(charsetUtf8, docNoCharset.select("meta[charset]").first().attr("charset"));
274 
275         final String htmlCharsetUTF8 = "<html>\n" +
276                                         " <head>\n" +
277                                         "  <meta charset=\"" + charsetUtf8 + "\">\n" +
278                                         " </head>\n" +
279                                         " <body></body>\n" +
280                                         "</html>";
281         assertEquals(htmlCharsetUTF8, docNoCharset.toString());
282     }
283 
284     @Test
testMetaCharsetUpdateDisabled()285     public void testMetaCharsetUpdateDisabled() {
286         final Document docDisabled = Document.createShell("");
287 
288         final String htmlNoCharset = "<html>\n" +
289                                         " <head></head>\n" +
290                                         " <body></body>\n" +
291                                         "</html>";
292         assertEquals(htmlNoCharset, docDisabled.toString());
293         assertNull(docDisabled.select("meta[charset]").first());
294     }
295 
296     @Test
testMetaCharsetUpdateDisabledNoChanges()297     public void testMetaCharsetUpdateDisabledNoChanges() {
298         final Document doc = createHtmlDocument("dontTouch");
299 
300         final String htmlCharset = "<html>\n" +
301                                     " <head>\n" +
302                                     "  <meta charset=\"dontTouch\">\n" +
303                                     "  <meta name=\"charset\" content=\"dontTouch\">\n" +
304                                     " </head>\n" +
305                                     " <body></body>\n" +
306                                     "</html>";
307         assertEquals(htmlCharset, doc.toString());
308 
309         Element selectedElement = doc.select("meta[charset]").first();
310         assertNotNull(selectedElement);
311         assertEquals("dontTouch", selectedElement.attr("charset"));
312 
313         selectedElement = doc.select("meta[name=charset]").first();
314         assertNotNull(selectedElement);
315         assertEquals("dontTouch", selectedElement.attr("content"));
316     }
317 
318     @Test
testMetaCharsetUpdateEnabledAfterCharsetChange()319     public void testMetaCharsetUpdateEnabledAfterCharsetChange() {
320         final Document doc = createHtmlDocument("dontTouch");
321         doc.charset(Charset.forName(charsetUtf8));
322 
323         Element selectedElement = doc.select("meta[charset]").first();
324         assertEquals(charsetUtf8, selectedElement.attr("charset"));
325         assertTrue(doc.select("meta[name=charset]").isEmpty());
326     }
327 
328     @Test
testMetaCharsetUpdateCleanup()329     public void testMetaCharsetUpdateCleanup() {
330         final Document doc = createHtmlDocument("dontTouch");
331         doc.updateMetaCharsetElement(true);
332         doc.charset(Charset.forName(charsetUtf8));
333 
334         final String htmlCharsetUTF8 = "<html>\n" +
335                                         " <head>\n" +
336                                         "  <meta charset=\"" + charsetUtf8 + "\">\n" +
337                                         " </head>\n" +
338                                         " <body></body>\n" +
339                                         "</html>";
340 
341         assertEquals(htmlCharsetUTF8, doc.toString());
342     }
343 
344     @Test
testMetaCharsetUpdateXmlUtf8()345     public void testMetaCharsetUpdateXmlUtf8() {
346         final Document doc = createXmlDocument("1.0", "changeThis", true);
347         doc.updateMetaCharsetElement(true);
348         doc.charset(Charset.forName(charsetUtf8));
349 
350         final String xmlCharsetUTF8 = "<?xml version=\"1.0\" encoding=\"" + charsetUtf8 + "\"?>\n" +
351                                         "<root>\n" +
352                                         " node\n" +
353                                         "</root>";
354         assertEquals(xmlCharsetUTF8, doc.toString());
355 
356         XmlDeclaration selectedNode = (XmlDeclaration) doc.childNode(0);
357         assertEquals(charsetUtf8, doc.charset().name());
358         assertEquals(charsetUtf8, selectedNode.attr("encoding"));
359         assertEquals(doc.charset(), doc.outputSettings().charset());
360     }
361 
362     @Test
testMetaCharsetUpdateXmlIso8859()363     public void testMetaCharsetUpdateXmlIso8859() {
364         final Document doc = createXmlDocument("1.0", "changeThis", true);
365         doc.updateMetaCharsetElement(true);
366         doc.charset(Charset.forName(charsetIso8859));
367 
368         final String xmlCharsetISO = "<?xml version=\"1.0\" encoding=\"" + charsetIso8859 + "\"?>\n" +
369                                         "<root>\n" +
370                                         " node\n" +
371                                         "</root>";
372         assertEquals(xmlCharsetISO, doc.toString());
373 
374         XmlDeclaration selectedNode = (XmlDeclaration) doc.childNode(0);
375         assertEquals(charsetIso8859, doc.charset().name());
376         assertEquals(charsetIso8859, selectedNode.attr("encoding"));
377         assertEquals(doc.charset(), doc.outputSettings().charset());
378     }
379 
380     @Test
testMetaCharsetUpdateXmlNoCharset()381     public void testMetaCharsetUpdateXmlNoCharset() {
382         final Document doc = createXmlDocument("1.0", "none", false);
383         doc.updateMetaCharsetElement(true);
384         doc.charset(Charset.forName(charsetUtf8));
385 
386         final String xmlCharsetUTF8 = "<?xml version=\"1.0\" encoding=\"" + charsetUtf8 + "\"?>\n" +
387                                         "<root>\n" +
388                                         " node\n" +
389                                         "</root>";
390         assertEquals(xmlCharsetUTF8, doc.toString());
391 
392         XmlDeclaration selectedNode = (XmlDeclaration) doc.childNode(0);
393         assertEquals(charsetUtf8, selectedNode.attr("encoding"));
394     }
395 
396     @Test
testMetaCharsetUpdateXmlDisabled()397     public void testMetaCharsetUpdateXmlDisabled() {
398         final Document doc = createXmlDocument("none", "none", false);
399 
400         final String xmlNoCharset = "<root>\n" +
401                                     " node\n" +
402                                     "</root>";
403         assertEquals(xmlNoCharset, doc.toString());
404     }
405 
406     @Test
testMetaCharsetUpdateXmlDisabledNoChanges()407     public void testMetaCharsetUpdateXmlDisabledNoChanges() {
408         final Document doc = createXmlDocument("dontTouch", "dontTouch", true);
409 
410         final String xmlCharset = "<?xml version=\"dontTouch\" encoding=\"dontTouch\"?>\n" +
411                                     "<root>\n" +
412                                     " node\n" +
413                                     "</root>";
414         assertEquals(xmlCharset, doc.toString());
415 
416         XmlDeclaration selectedNode = (XmlDeclaration) doc.childNode(0);
417         assertEquals("dontTouch", selectedNode.attr("encoding"));
418         assertEquals("dontTouch", selectedNode.attr("version"));
419     }
420 
421     @Test
testMetaCharsetUpdatedDisabledPerDefault()422     public void testMetaCharsetUpdatedDisabledPerDefault() {
423         final Document doc = createHtmlDocument("none");
424         assertFalse(doc.updateMetaCharsetElement());
425     }
426 
createHtmlDocument(String charset)427     private Document createHtmlDocument(String charset) {
428         final Document doc = Document.createShell("");
429         doc.head().appendElement("meta").attr("charset", charset);
430         doc.head().appendElement("meta").attr("name", "charset").attr("content", charset);
431 
432         return doc;
433     }
434 
createXmlDocument(String version, String charset, boolean addDecl)435     private Document createXmlDocument(String version, String charset, boolean addDecl) {
436         final Document doc = new Document("");
437         doc.appendElement("root").text("node");
438         doc.outputSettings().syntax(Syntax.xml);
439 
440         if(addDecl) {
441             XmlDeclaration decl = new XmlDeclaration("xml", false);
442             decl.attr("version", version);
443             decl.attr("encoding", charset);
444             doc.prependChild(decl);
445         }
446 
447         return doc;
448     }
449 
450     @Test
testShiftJisRoundtrip()451     public void testShiftJisRoundtrip() throws Exception {
452         String input =
453                 "<html>"
454                         +   "<head>"
455                         +     "<meta http-equiv=\"content-type\" content=\"text/html; charset=Shift_JIS\" />"
456                         +   "</head>"
457                         +   "<body>"
458                         +     "before&nbsp;after"
459                         +   "</body>"
460                         + "</html>";
461         InputStream is = new ByteArrayInputStream(input.getBytes(StandardCharsets.US_ASCII));
462 
463         Document doc = Jsoup.parse(is, null, "http://example.com");
464         doc.outputSettings().escapeMode(Entities.EscapeMode.xhtml);
465 
466         String output = new String(doc.html().getBytes(doc.outputSettings().charset()), doc.outputSettings().charset());
467 
468         assertFalse(output.contains("?"), "Should not have contained a '?'.");
469         assertTrue(output.contains("&#xa0;") || output.contains("&nbsp;"),
470                 "Should have contained a '&#xa0;' or a '&nbsp;'.");
471     }
472 
parseAndHtmlOnDifferentThreads()473     @Test public void parseAndHtmlOnDifferentThreads() throws InterruptedException {
474         String html = "<p>Alrighty then it's not \uD83D\uDCA9. <span>Next</span></p>"; // ��
475         String asci = "<p>Alrighty then it's not &#x1f4a9;. <span>Next</span></p>";
476 
477         final Document doc = Jsoup.parse(html);
478         final String[] out = new String[1];
479         final Elements p = doc.select("p");
480         assertEquals(html, p.outerHtml());
481 
482         Thread thread = new Thread(() -> {
483             out[0] = p.outerHtml();
484             doc.outputSettings().charset(StandardCharsets.US_ASCII);
485         });
486         thread.start();
487         thread.join();
488 
489         assertEquals(html, out[0]);
490         assertEquals(StandardCharsets.US_ASCII, doc.outputSettings().charset());
491         assertEquals(asci, p.outerHtml());
492     }
493 
testDocumentTypeGet()494     @Test public void testDocumentTypeGet() {
495         String html = "\n\n<!-- comment -->  <!doctype html><p>One</p>";
496         Document doc = Jsoup.parse(html);
497         DocumentType documentType = doc.documentType();
498         assertNotNull(documentType);
499         assertEquals("html", documentType.name());
500     }
501 
framesetSupportsBodyMethod()502     @Test public void framesetSupportsBodyMethod() {
503         String html = "<html><head><title>Frame Test</title></head><frameset id=id><frame src=foo.html></frameset>";
504         Document doc = Jsoup.parse(html);
505         Element head = doc.head();
506         assertNotNull(head);
507         assertEquals("Frame Test", doc.title());
508 
509         // Frameset docs per html5 spec have no body element - but instead a frameset elelemt
510         assertNull(doc.selectFirst("body"));
511         Element frameset = doc.selectFirst("frameset");
512         assertNotNull(frameset);
513 
514         // the body() method returns body or frameset and does not otherwise modify the document
515         // doing it in body() vs parse keeps the html close to original for round-trip option
516         Element body = doc.body();
517         assertNotNull(body);
518         assertSame(frameset, body);
519         assertEquals("frame", body.child(0).tagName());
520 
521         assertNull(doc.selectFirst("body")); // did not vivify a body element
522 
523         String expected = "<html>\n" +
524             " <head>\n" +
525             "  <title>Frame Test</title>\n" +
526             " </head>\n" +
527             " <frameset id=\"id\">\n" +
528             "  <frame src=\"foo.html\">\n" +
529             " </frameset>\n" +
530             "</html>";
531         assertEquals(expected, doc.html());
532     }
533 
forms()534     @Test void forms() {
535         String html = "<body><form id=1><input name=foo></form><form id=2><input name=bar>";
536         Document doc = Jsoup.parse(html);
537 
538         List<FormElement> forms = doc.forms();
539         assertEquals(2, forms.size());
540         FormElement form = forms.get(1);
541         assertEquals(1, form.elements().size());
542         assertEquals("bar", form.elements().first().attr("name"));
543 
544         String emptyHtml = "<body>";
545         Document emptyDoc = Jsoup.parse(emptyHtml);
546         assertEquals(0, emptyDoc.forms().size());
547     }
548 
expectForm()549     @Test void expectForm() {
550         String html = "<body><div name=form></div><form id=1 name=form><input name=foo></form><form id=2><input name=bar>";
551         Document doc = Jsoup.parse(html);
552 
553         // test finds first <form>
554         FormElement formEl1 = doc.expectForm("[name=form]");
555         assertEquals("1", formEl1.id()); // and not the div
556 
557         FormElement formEl2 = doc.expectForm("form");
558         assertEquals("1", formEl2.id());
559 
560         FormElement formEl3 = doc.expectForm("form:has([name=bar])");
561         assertEquals("2", formEl3.id());
562 
563         boolean threw = false;
564         try {
565             FormElement nix = doc.expectForm("div");
566         } catch (IllegalArgumentException e) {
567             threw = true;
568         }
569         assertTrue(threw);
570 
571     }
572 }
573