1 package org.jsoup.select; 2 3 import org.jsoup.Jsoup; 4 import org.jsoup.nodes.Document; 5 import org.jsoup.parser.Tag; 6 import org.junit.jupiter.api.BeforeAll; 7 import org.junit.jupiter.api.BeforeEach; 8 import org.junit.jupiter.api.Test; 9 10 import static org.junit.jupiter.api.Assertions.*; 11 12 13 public class CssTest { 14 15 private Document html = null; 16 private static String htmlString; 17 18 @BeforeAll initClass()19 public static void initClass() { 20 StringBuilder sb = new StringBuilder("<html><head></head><body>"); 21 22 sb.append("<div id='pseudo'>"); 23 for (int i = 1; i <= 10; i++) { 24 sb.append(String.format("<p>%d</p>",i)); 25 } 26 sb.append("</div>"); 27 28 sb.append("<div id='type'>"); 29 for (int i = 1; i <= 10; i++) { 30 sb.append(String.format("<p>%d</p>",i)); 31 sb.append(String.format("<span>%d</span>",i)); 32 sb.append(String.format("<em>%d</em>",i)); 33 sb.append(String.format("<svg>%d</svg>",i)); 34 } 35 sb.append("</div>"); 36 37 sb.append("<span id='onlySpan'><br /></span>"); 38 sb.append("<p class='empty'><!-- Comment only is still empty! --></p>"); 39 40 sb.append("<div id='only'>"); 41 sb.append("Some text before the <em>only</em> child in this div"); 42 sb.append("</div>"); 43 44 sb.append("</body></html>"); 45 htmlString = sb.toString(); 46 } 47 48 @BeforeEach init()49 public void init() { 50 html = Jsoup.parse(htmlString); 51 } 52 53 @Test firstChild()54 public void firstChild() { 55 check(html.select("#pseudo :first-child"), "1"); 56 check(html.select("html:first-child")); 57 } 58 59 @Test lastChild()60 public void lastChild() { 61 check(html.select("#pseudo :last-child"), "10"); 62 check(html.select("html:last-child")); 63 } 64 65 @Test nthChild_simple()66 public void nthChild_simple() { 67 for(int i = 1; i <=10; i++) { 68 check(html.select(String.format("#pseudo :nth-child(%d)", i)), String.valueOf(i)); 69 } 70 } 71 72 @Test nthOfType_unknownTag()73 public void nthOfType_unknownTag() { 74 for(int i = 1; i <=10; i++) { 75 check(html.select(String.format("#type svg:nth-of-type(%d)", i)), String.valueOf(i)); 76 } 77 } 78 79 @Test nthLastChild_simple()80 public void nthLastChild_simple() { 81 for(int i = 1; i <=10; i++) { 82 check(html.select(String.format("#pseudo :nth-last-child(%d)", i)), String.valueOf(11-i)); 83 } 84 } 85 86 @Test nthOfType_simple()87 public void nthOfType_simple() { 88 for(int i = 1; i <=10; i++) { 89 check(html.select(String.format("#type p:nth-of-type(%d)", i)), String.valueOf(i)); 90 } 91 } 92 93 @Test nthLastOfType_simple()94 public void nthLastOfType_simple() { 95 for(int i = 1; i <=10; i++) { 96 check(html.select(String.format("#type :nth-last-of-type(%d)", i)), String.valueOf(11-i),String.valueOf(11-i),String.valueOf(11-i),String.valueOf(11-i)); 97 } 98 } 99 100 @Test nthChild_advanced()101 public void nthChild_advanced() { 102 check(html.select("#pseudo :nth-child(-5)")); 103 check(html.select("#pseudo :nth-child(odd)"), "1", "3", "5", "7", "9"); 104 check(html.select("#pseudo :nth-child(2n-1)"), "1", "3", "5", "7", "9"); 105 check(html.select("#pseudo :nth-child(2n+1)"), "1", "3", "5", "7", "9"); 106 check(html.select("#pseudo :nth-child(2n+3)"), "3", "5", "7", "9"); 107 check(html.select("#pseudo :nth-child(even)"), "2", "4", "6", "8", "10"); 108 check(html.select("#pseudo :nth-child(2n)"), "2", "4", "6", "8", "10"); 109 check(html.select("#pseudo :nth-child(3n-1)"), "2", "5", "8"); 110 check(html.select("#pseudo :nth-child(-2n+5)"), "1", "3", "5"); 111 check(html.select("#pseudo :nth-child(+5)"), "5"); 112 } 113 114 @Test nthOfType_advanced()115 public void nthOfType_advanced() { 116 check(html.select("#type :nth-of-type(-5)")); 117 check(html.select("#type p:nth-of-type(odd)"), "1", "3", "5", "7", "9"); 118 check(html.select("#type em:nth-of-type(2n-1)"), "1", "3", "5", "7", "9"); 119 check(html.select("#type p:nth-of-type(2n+1)"), "1", "3", "5", "7", "9"); 120 check(html.select("#type span:nth-of-type(2n+3)"), "3", "5", "7", "9"); 121 check(html.select("#type p:nth-of-type(even)"), "2", "4", "6", "8", "10"); 122 check(html.select("#type p:nth-of-type(2n)"), "2", "4", "6", "8", "10"); 123 check(html.select("#type p:nth-of-type(3n-1)"), "2", "5", "8"); 124 check(html.select("#type p:nth-of-type(-2n+5)"), "1", "3", "5"); 125 check(html.select("#type :nth-of-type(+5)"), "5", "5", "5", "5"); 126 } 127 128 129 @Test nthLastChild_advanced()130 public void nthLastChild_advanced() { 131 check(html.select("#pseudo :nth-last-child(-5)")); 132 check(html.select("#pseudo :nth-last-child(odd)"), "2", "4", "6", "8", "10"); 133 check(html.select("#pseudo :nth-last-child(2n-1)"), "2", "4", "6", "8", "10"); 134 check(html.select("#pseudo :nth-last-child(2n+1)"), "2", "4", "6", "8", "10"); 135 check(html.select("#pseudo :nth-last-child(2n+3)"), "2", "4", "6", "8"); 136 check(html.select("#pseudo :nth-last-child(even)"), "1", "3", "5", "7", "9"); 137 check(html.select("#pseudo :nth-last-child(2n)"), "1", "3", "5", "7", "9"); 138 check(html.select("#pseudo :nth-last-child(3n-1)"), "3", "6", "9"); 139 140 check(html.select("#pseudo :nth-last-child(-2n+5)"), "6", "8", "10"); 141 check(html.select("#pseudo :nth-last-child(+5)"), "6"); 142 } 143 144 @Test nthLastOfType_advanced()145 public void nthLastOfType_advanced() { 146 check(html.select("#type :nth-last-of-type(-5)")); 147 check(html.select("#type p:nth-last-of-type(odd)"), "2", "4", "6", "8", "10"); 148 check(html.select("#type em:nth-last-of-type(2n-1)"), "2", "4", "6", "8", "10"); 149 check(html.select("#type p:nth-last-of-type(2n+1)"), "2", "4", "6", "8", "10"); 150 check(html.select("#type span:nth-last-of-type(2n+3)"), "2", "4", "6", "8"); 151 check(html.select("#type p:nth-last-of-type(even)"), "1", "3", "5", "7", "9"); 152 check(html.select("#type p:nth-last-of-type(2n)"), "1", "3", "5", "7", "9"); 153 check(html.select("#type p:nth-last-of-type(3n-1)"), "3", "6", "9"); 154 155 check(html.select("#type span:nth-last-of-type(-2n+5)"), "6", "8", "10"); 156 check(html.select("#type :nth-last-of-type(+5)"), "6", "6", "6", "6"); 157 } 158 159 @Test firstOfType()160 public void firstOfType() { 161 check(html.select("div:not(#only) :first-of-type"), "1", "1", "1", "1", "1"); 162 } 163 164 @Test lastOfType()165 public void lastOfType() { 166 check(html.select("div:not(#only) :last-of-type"), "10", "10", "10", "10", "10"); 167 } 168 169 @Test empty()170 public void empty() { 171 final Elements sel = html.select(":empty"); 172 assertEquals(3, sel.size()); 173 assertEquals("head", sel.get(0).tagName()); 174 assertEquals("br", sel.get(1).tagName()); 175 assertEquals("p", sel.get(2).tagName()); 176 } 177 178 @Test onlyChild()179 public void onlyChild() { 180 final Elements sel = html.select("span :only-child"); 181 assertEquals(1, sel.size()); 182 assertEquals("br", sel.get(0).tagName()); 183 184 check(html.select("#only :only-child"), "only"); 185 } 186 187 @Test onlyOfType()188 public void onlyOfType() { 189 final Elements sel = html.select(":only-of-type"); 190 assertEquals(6, sel.size()); 191 assertEquals("head", sel.get(0).tagName()); 192 assertEquals("body", sel.get(1).tagName()); 193 assertEquals("span", sel.get(2).tagName()); 194 assertEquals("br", sel.get(3).tagName()); 195 assertEquals("p", sel.get(4).tagName()); 196 assertTrue(sel.get(4).hasClass("empty")); 197 assertEquals("em", sel.get(5).tagName()); 198 } 199 check(Elements result, String...expectedContent )200 protected void check(Elements result, String...expectedContent ) { 201 assertEquals(expectedContent.length, result.size(), "Number of elements"); 202 for (int i = 0; i < expectedContent.length; i++) { 203 assertNotNull(result.get(i)); 204 assertEquals(expectedContent[i], result.get(i).ownText(), "Expected element"); 205 } 206 } 207 208 @Test root()209 public void root() { 210 Elements sel = html.select(":root"); 211 assertEquals(1, sel.size()); 212 assertNotNull(sel.get(0)); 213 assertEquals(Tag.valueOf("html"), sel.get(0).tag()); 214 215 Elements sel2 = html.select("body").select(":root"); 216 assertEquals(1, sel2.size()); 217 assertNotNull(sel2.get(0)); 218 assertEquals(Tag.valueOf("body"), sel2.get(0).tag()); 219 } 220 221 } 222