PageRenderTime 46ms CodeModel.GetById 1ms RepoModel.GetById 1ms app.codeStats 0ms

/actionpack/test/controller/selector_test.rb

https://github.com/ghar/rails
Ruby | 629 lines | 473 code | 72 blank | 84 comment | 0 complexity | f8bedb1c282888f8e76188781e174bc1 MD5 | raw file
  1. #--
  2. # Copyright (c) 2006 Assaf Arkin (http://labnotes.org)
  3. # Under MIT and/or CC By license.
  4. #++
  5. require 'abstract_unit'
  6. require 'controller/fake_controllers'
  7. require 'action_controller/vendor/html-scanner'
  8. class SelectorTest < Test::Unit::TestCase
  9. #
  10. # Basic selector: element, id, class, attributes.
  11. #
  12. def test_element
  13. parse(%Q{<div id="1"></div><p></p><div id="2"></div>})
  14. # Match element by name.
  15. select("div")
  16. assert_equal 2, @matches.size
  17. assert_equal "1", @matches[0].attributes["id"]
  18. assert_equal "2", @matches[1].attributes["id"]
  19. # Not case sensitive.
  20. select("DIV")
  21. assert_equal 2, @matches.size
  22. assert_equal "1", @matches[0].attributes["id"]
  23. assert_equal "2", @matches[1].attributes["id"]
  24. # Universal match (all elements).
  25. select("*")
  26. assert_equal 3, @matches.size
  27. assert_equal "1", @matches[0].attributes["id"]
  28. assert_equal nil, @matches[1].attributes["id"]
  29. assert_equal "2", @matches[2].attributes["id"]
  30. end
  31. def test_identifier
  32. parse(%Q{<div id="1"></div><p></p><div id="2"></div>})
  33. # Match element by ID.
  34. select("div#1")
  35. assert_equal 1, @matches.size
  36. assert_equal "1", @matches[0].attributes["id"]
  37. # Match element by ID, substitute value.
  38. select("div#?", 2)
  39. assert_equal 1, @matches.size
  40. assert_equal "2", @matches[0].attributes["id"]
  41. # Element name does not match ID.
  42. select("p#?", 2)
  43. assert_equal 0, @matches.size
  44. # Use regular expression.
  45. select("#?", /\d/)
  46. assert_equal 2, @matches.size
  47. end
  48. def test_class_name
  49. parse(%Q{<div id="1" class=" foo "></div><p id="2" class=" foo bar "></p><div id="3" class="bar"></div>})
  50. # Match element with specified class.
  51. select("div.foo")
  52. assert_equal 1, @matches.size
  53. assert_equal "1", @matches[0].attributes["id"]
  54. # Match any element with specified class.
  55. select("*.foo")
  56. assert_equal 2, @matches.size
  57. assert_equal "1", @matches[0].attributes["id"]
  58. assert_equal "2", @matches[1].attributes["id"]
  59. # Match elements with other class.
  60. select("*.bar")
  61. assert_equal 2, @matches.size
  62. assert_equal "2", @matches[0].attributes["id"]
  63. assert_equal "3", @matches[1].attributes["id"]
  64. # Match only element with both class names.
  65. select("*.bar.foo")
  66. assert_equal 1, @matches.size
  67. assert_equal "2", @matches[0].attributes["id"]
  68. end
  69. def test_attribute
  70. parse(%Q{<div id="1"></div><p id="2" title="" bar="foo"></p><div id="3" title="foo"></div>})
  71. # Match element with attribute.
  72. select("div[title]")
  73. assert_equal 1, @matches.size
  74. assert_equal "3", @matches[0].attributes["id"]
  75. # Match any element with attribute.
  76. select("*[title]")
  77. assert_equal 2, @matches.size
  78. assert_equal "2", @matches[0].attributes["id"]
  79. assert_equal "3", @matches[1].attributes["id"]
  80. # Match element with attribute value.
  81. select("*[title=foo]")
  82. assert_equal 1, @matches.size
  83. assert_equal "3", @matches[0].attributes["id"]
  84. # Match element with attribute and attribute value.
  85. select("[bar=foo][title]")
  86. assert_equal 1, @matches.size
  87. assert_equal "2", @matches[0].attributes["id"]
  88. # Not case sensitive.
  89. select("[BAR=foo][TiTle]")
  90. assert_equal 1, @matches.size
  91. assert_equal "2", @matches[0].attributes["id"]
  92. end
  93. def test_attribute_quoted
  94. parse(%Q{<div id="1" title="foo"></div><div id="2" title="bar"></div><div id="3" title=" bar "></div>})
  95. # Match without quotes.
  96. select("[title = bar]")
  97. assert_equal 1, @matches.size
  98. assert_equal "2", @matches[0].attributes["id"]
  99. # Match with single quotes.
  100. select("[title = 'bar' ]")
  101. assert_equal 1, @matches.size
  102. assert_equal "2", @matches[0].attributes["id"]
  103. # Match with double quotes.
  104. select("[title = \"bar\" ]")
  105. assert_equal 1, @matches.size
  106. assert_equal "2", @matches[0].attributes["id"]
  107. # Match with spaces.
  108. select("[title = \" bar \" ]")
  109. assert_equal 1, @matches.size
  110. assert_equal "3", @matches[0].attributes["id"]
  111. end
  112. def test_attribute_equality
  113. parse(%Q{<div id="1" title="foo bar"></div><div id="2" title="barbaz"></div>})
  114. # Match (fail) complete value.
  115. select("[title=bar]")
  116. assert_equal 0, @matches.size
  117. # Match space-separate word.
  118. select("[title~=foo]")
  119. assert_equal 1, @matches.size
  120. assert_equal "1", @matches[0].attributes["id"]
  121. select("[title~=bar]")
  122. assert_equal 1, @matches.size
  123. assert_equal "1", @matches[0].attributes["id"]
  124. # Match beginning of value.
  125. select("[title^=ba]")
  126. assert_equal 1, @matches.size
  127. assert_equal "2", @matches[0].attributes["id"]
  128. # Match end of value.
  129. select("[title$=ar]")
  130. assert_equal 1, @matches.size
  131. assert_equal "1", @matches[0].attributes["id"]
  132. # Match text in value.
  133. select("[title*=bar]")
  134. assert_equal 2, @matches.size
  135. assert_equal "1", @matches[0].attributes["id"]
  136. assert_equal "2", @matches[1].attributes["id"]
  137. # Match first space separated word.
  138. select("[title|=foo]")
  139. assert_equal 1, @matches.size
  140. assert_equal "1", @matches[0].attributes["id"]
  141. select("[title|=bar]")
  142. assert_equal 0, @matches.size
  143. end
  144. #
  145. # Selector composition: groups, sibling, children
  146. #
  147. def test_selector_group
  148. parse(%Q{<h1 id="1"></h1><h2 id="2"></h2><h3 id="3"></h3>})
  149. # Simple group selector.
  150. select("h1,h3")
  151. assert_equal 2, @matches.size
  152. assert_equal "1", @matches[0].attributes["id"]
  153. assert_equal "3", @matches[1].attributes["id"]
  154. select("h1 , h3")
  155. assert_equal 2, @matches.size
  156. assert_equal "1", @matches[0].attributes["id"]
  157. assert_equal "3", @matches[1].attributes["id"]
  158. # Complex group selector.
  159. parse(%Q{<h1 id="1"><a href="foo"></a></h1><h2 id="2"><a href="bar"></a></h2><h3 id="2"><a href="baz"></a></h3>})
  160. select("h1 a, h3 a")
  161. assert_equal 2, @matches.size
  162. assert_equal "foo", @matches[0].attributes["href"]
  163. assert_equal "baz", @matches[1].attributes["href"]
  164. # And now for the three selector challenge.
  165. parse(%Q{<h1 id="1"><a href="foo"></a></h1><h2 id="2"><a href="bar"></a></h2><h3 id="2"><a href="baz"></a></h3>})
  166. select("h1 a, h2 a, h3 a")
  167. assert_equal 3, @matches.size
  168. assert_equal "foo", @matches[0].attributes["href"]
  169. assert_equal "bar", @matches[1].attributes["href"]
  170. assert_equal "baz", @matches[2].attributes["href"]
  171. end
  172. def test_sibling_selector
  173. parse(%Q{<h1 id="1"></h1><h2 id="2"></h2><h3 id="3"></h3>})
  174. # Test next sibling.
  175. select("h1+*")
  176. assert_equal 1, @matches.size
  177. assert_equal "2", @matches[0].attributes["id"]
  178. select("h1+h2")
  179. assert_equal 1, @matches.size
  180. assert_equal "2", @matches[0].attributes["id"]
  181. select("h1+h3")
  182. assert_equal 0, @matches.size
  183. select("*+h3")
  184. assert_equal 1, @matches.size
  185. assert_equal "3", @matches[0].attributes["id"]
  186. # Test any sibling.
  187. select("h1~*")
  188. assert_equal 2, @matches.size
  189. assert_equal "2", @matches[0].attributes["id"]
  190. assert_equal "3", @matches[1].attributes["id"]
  191. select("h2~*")
  192. assert_equal 1, @matches.size
  193. assert_equal "3", @matches[0].attributes["id"]
  194. end
  195. def test_children_selector
  196. parse(%Q{<div><p id="1"><span id="2"></span></p></div><div><p id="3"><span id="4" class="foo"></span></p></div>})
  197. # Test child selector.
  198. select("div>p")
  199. assert_equal 2, @matches.size
  200. assert_equal "1", @matches[0].attributes["id"]
  201. assert_equal "3", @matches[1].attributes["id"]
  202. select("div>span")
  203. assert_equal 0, @matches.size
  204. select("div>p#3")
  205. assert_equal 1, @matches.size
  206. assert_equal "3", @matches[0].attributes["id"]
  207. select("div>p>span")
  208. assert_equal 2, @matches.size
  209. assert_equal "2", @matches[0].attributes["id"]
  210. assert_equal "4", @matches[1].attributes["id"]
  211. # Test descendant selector.
  212. select("div p")
  213. assert_equal 2, @matches.size
  214. assert_equal "1", @matches[0].attributes["id"]
  215. assert_equal "3", @matches[1].attributes["id"]
  216. select("div span")
  217. assert_equal 2, @matches.size
  218. assert_equal "2", @matches[0].attributes["id"]
  219. assert_equal "4", @matches[1].attributes["id"]
  220. select("div *#3")
  221. assert_equal 1, @matches.size
  222. assert_equal "3", @matches[0].attributes["id"]
  223. select("div *#4")
  224. assert_equal 1, @matches.size
  225. assert_equal "4", @matches[0].attributes["id"]
  226. # This is here because it failed before when whitespaces
  227. # were not properly stripped.
  228. select("div .foo")
  229. assert_equal 1, @matches.size
  230. assert_equal "4", @matches[0].attributes["id"]
  231. end
  232. #
  233. # Pseudo selectors: root, nth-child, empty, content, etc
  234. #
  235. def test_root_selector
  236. parse(%Q{<div id="1"><div id="2"></div></div>})
  237. # Can only find element if it's root.
  238. select(":root")
  239. assert_equal 1, @matches.size
  240. assert_equal "1", @matches[0].attributes["id"]
  241. select("#1:root")
  242. assert_equal 1, @matches.size
  243. assert_equal "1", @matches[0].attributes["id"]
  244. select("#2:root")
  245. assert_equal 0, @matches.size
  246. # Opposite for nth-child.
  247. select("#1:nth-child(1)")
  248. assert_equal 0, @matches.size
  249. end
  250. def test_nth_child_odd_even
  251. parse(%Q{<table><tr id="1"></tr><tr id="2"></tr><tr id="3"></tr><tr id="4"></tr></table>})
  252. # Test odd nth children.
  253. select("tr:nth-child(odd)")
  254. assert_equal 2, @matches.size
  255. assert_equal "1", @matches[0].attributes["id"]
  256. assert_equal "3", @matches[1].attributes["id"]
  257. # Test even nth children.
  258. select("tr:nth-child(even)")
  259. assert_equal 2, @matches.size
  260. assert_equal "2", @matches[0].attributes["id"]
  261. assert_equal "4", @matches[1].attributes["id"]
  262. end
  263. def test_nth_child_a_is_zero
  264. parse(%Q{<table><tr id="1"></tr><tr id="2"></tr><tr id="3"></tr><tr id="4"></tr></table>})
  265. # Test the third child.
  266. select("tr:nth-child(0n+3)")
  267. assert_equal 1, @matches.size
  268. assert_equal "3", @matches[0].attributes["id"]
  269. # Same but an can be omitted when zero.
  270. select("tr:nth-child(3)")
  271. assert_equal 1, @matches.size
  272. assert_equal "3", @matches[0].attributes["id"]
  273. # Second element (but not every second element).
  274. select("tr:nth-child(0n+2)")
  275. assert_equal 1, @matches.size
  276. assert_equal "2", @matches[0].attributes["id"]
  277. # Before first and past last returns nothing.:
  278. assert_raise(ArgumentError) { select("tr:nth-child(-1)") }
  279. select("tr:nth-child(0)")
  280. assert_equal 0, @matches.size
  281. select("tr:nth-child(5)")
  282. assert_equal 0, @matches.size
  283. end
  284. def test_nth_child_a_is_one
  285. parse(%Q{<table><tr id="1"></tr><tr id="2"></tr><tr id="3"></tr><tr id="4"></tr></table>})
  286. # a is group of one, pick every element in group.
  287. select("tr:nth-child(1n+0)")
  288. assert_equal 4, @matches.size
  289. # Same but a can be omitted when one.
  290. select("tr:nth-child(n+0)")
  291. assert_equal 4, @matches.size
  292. # Same but b can be omitted when zero.
  293. select("tr:nth-child(n)")
  294. assert_equal 4, @matches.size
  295. end
  296. def test_nth_child_b_is_zero
  297. parse(%Q{<table><tr id="1"></tr><tr id="2"></tr><tr id="3"></tr><tr id="4"></tr></table>})
  298. # If b is zero, pick the n-th element (here each one).
  299. select("tr:nth-child(n+0)")
  300. assert_equal 4, @matches.size
  301. # If b is zero, pick the n-th element (here every second).
  302. select("tr:nth-child(2n+0)")
  303. assert_equal 2, @matches.size
  304. assert_equal "1", @matches[0].attributes["id"]
  305. assert_equal "3", @matches[1].attributes["id"]
  306. # If a and b are both zero, no element selected.
  307. select("tr:nth-child(0n+0)")
  308. assert_equal 0, @matches.size
  309. select("tr:nth-child(0)")
  310. assert_equal 0, @matches.size
  311. end
  312. def test_nth_child_a_is_negative
  313. parse(%Q{<table><tr id="1"></tr><tr id="2"></tr><tr id="3"></tr><tr id="4"></tr></table>})
  314. # Since a is -1, picks the first three elements.
  315. select("tr:nth-child(-n+3)")
  316. assert_equal 3, @matches.size
  317. assert_equal "1", @matches[0].attributes["id"]
  318. assert_equal "2", @matches[1].attributes["id"]
  319. assert_equal "3", @matches[2].attributes["id"]
  320. # Since a is -2, picks the first in every second of first four elements.
  321. select("tr:nth-child(-2n+3)")
  322. assert_equal 2, @matches.size
  323. assert_equal "1", @matches[0].attributes["id"]
  324. assert_equal "3", @matches[1].attributes["id"]
  325. # Since a is -2, picks the first in every second of first three elements.
  326. select("tr:nth-child(-2n+2)")
  327. assert_equal 1, @matches.size
  328. assert_equal "1", @matches[0].attributes["id"]
  329. end
  330. def test_nth_child_b_is_negative
  331. parse(%Q{<table><tr id="1"></tr><tr id="2"></tr><tr id="3"></tr><tr id="4"></tr></table>})
  332. # Select last of four.
  333. select("tr:nth-child(4n-1)")
  334. assert_equal 1, @matches.size
  335. assert_equal "4", @matches[0].attributes["id"]
  336. # Select first of four.
  337. select("tr:nth-child(4n-4)")
  338. assert_equal 1, @matches.size
  339. assert_equal "1", @matches[0].attributes["id"]
  340. # Select last of every second.
  341. select("tr:nth-child(2n-1)")
  342. assert_equal 2, @matches.size
  343. assert_equal "2", @matches[0].attributes["id"]
  344. assert_equal "4", @matches[1].attributes["id"]
  345. # Select nothing since an+b always < 0
  346. select("tr:nth-child(-1n-1)")
  347. assert_equal 0, @matches.size
  348. end
  349. def test_nth_child_substitution_values
  350. parse(%Q{<table><tr id="1"></tr><tr id="2"></tr><tr id="3"></tr><tr id="4"></tr></table>})
  351. # Test with ?n?.
  352. select("tr:nth-child(?n?)", 2, 1)
  353. assert_equal 2, @matches.size
  354. assert_equal "1", @matches[0].attributes["id"]
  355. assert_equal "3", @matches[1].attributes["id"]
  356. select("tr:nth-child(?n?)", 2, 2)
  357. assert_equal 2, @matches.size
  358. assert_equal "2", @matches[0].attributes["id"]
  359. assert_equal "4", @matches[1].attributes["id"]
  360. select("tr:nth-child(?n?)", 4, 2)
  361. assert_equal 1, @matches.size
  362. assert_equal "2", @matches[0].attributes["id"]
  363. # Test with ? (b only).
  364. select("tr:nth-child(?)", 3)
  365. assert_equal 1, @matches.size
  366. assert_equal "3", @matches[0].attributes["id"]
  367. select("tr:nth-child(?)", 5)
  368. assert_equal 0, @matches.size
  369. end
  370. def test_nth_last_child
  371. parse(%Q{<table><tr id="1"></tr><tr id="2"></tr><tr id="3"></tr><tr id="4"></tr></table>})
  372. # Last two elements.
  373. select("tr:nth-last-child(-n+2)")
  374. assert_equal 2, @matches.size
  375. assert_equal "3", @matches[0].attributes["id"]
  376. assert_equal "4", @matches[1].attributes["id"]
  377. # All old elements counting from last one.
  378. select("tr:nth-last-child(odd)")
  379. assert_equal 2, @matches.size
  380. assert_equal "2", @matches[0].attributes["id"]
  381. assert_equal "4", @matches[1].attributes["id"]
  382. end
  383. def test_nth_of_type
  384. parse(%Q{<table><thead></thead><tr id="1"></tr><tr id="2"></tr><tr id="3"></tr><tr id="4"></tr></table>})
  385. # First two elements.
  386. select("tr:nth-of-type(-n+2)")
  387. assert_equal 2, @matches.size
  388. assert_equal "1", @matches[0].attributes["id"]
  389. assert_equal "2", @matches[1].attributes["id"]
  390. # All old elements counting from last one.
  391. select("tr:nth-last-of-type(odd)")
  392. assert_equal 2, @matches.size
  393. assert_equal "2", @matches[0].attributes["id"]
  394. assert_equal "4", @matches[1].attributes["id"]
  395. end
  396. def test_first_and_last
  397. parse(%Q{<table><thead></thead><tr id="1"></tr><tr id="2"></tr><tr id="3"></tr><tr id="4"></tr></table>})
  398. # First child.
  399. select("tr:first-child")
  400. assert_equal 0, @matches.size
  401. select(":first-child")
  402. assert_equal 1, @matches.size
  403. assert_equal "thead", @matches[0].name
  404. # First of type.
  405. select("tr:first-of-type")
  406. assert_equal 1, @matches.size
  407. assert_equal "1", @matches[0].attributes["id"]
  408. select("thead:first-of-type")
  409. assert_equal 1, @matches.size
  410. assert_equal "thead", @matches[0].name
  411. select("div:first-of-type")
  412. assert_equal 0, @matches.size
  413. # Last child.
  414. select("tr:last-child")
  415. assert_equal 1, @matches.size
  416. assert_equal "4", @matches[0].attributes["id"]
  417. # Last of type.
  418. select("tr:last-of-type")
  419. assert_equal 1, @matches.size
  420. assert_equal "4", @matches[0].attributes["id"]
  421. select("thead:last-of-type")
  422. assert_equal 1, @matches.size
  423. assert_equal "thead", @matches[0].name
  424. select("div:last-of-type")
  425. assert_equal 0, @matches.size
  426. end
  427. def test_only_child_and_only_type_first_and_last
  428. # Only child.
  429. parse(%Q{<table><tr></tr></table>})
  430. select("table:only-child")
  431. assert_equal 0, @matches.size
  432. select("tr:only-child")
  433. assert_equal 1, @matches.size
  434. assert_equal "tr", @matches[0].name
  435. parse(%Q{<table><tr></tr><tr></tr></table>})
  436. select("tr:only-child")
  437. assert_equal 0, @matches.size
  438. # Only of type.
  439. parse(%Q{<table><thead></thead><tr></tr><tr></tr></table>})
  440. select("thead:only-of-type")
  441. assert_equal 1, @matches.size
  442. assert_equal "thead", @matches[0].name
  443. select("td:only-of-type")
  444. assert_equal 0, @matches.size
  445. end
  446. def test_empty
  447. parse(%Q{<table><tr></tr></table>})
  448. select("table:empty")
  449. assert_equal 0, @matches.size
  450. select("tr:empty")
  451. assert_equal 1, @matches.size
  452. parse(%Q{<div> </div>})
  453. select("div:empty")
  454. assert_equal 1, @matches.size
  455. end
  456. def test_content
  457. parse(%Q{<div> </div>})
  458. select("div:content()")
  459. assert_equal 1, @matches.size
  460. parse(%Q{<div>something </div>})
  461. select("div:content()")
  462. assert_equal 0, @matches.size
  463. select("div:content(something)")
  464. assert_equal 1, @matches.size
  465. select("div:content( 'something' )")
  466. assert_equal 1, @matches.size
  467. select("div:content( \"something\" )")
  468. assert_equal 1, @matches.size
  469. select("div:content(?)", "something")
  470. assert_equal 1, @matches.size
  471. select("div:content(?)", /something/)
  472. assert_equal 1, @matches.size
  473. end
  474. #
  475. # Test negation.
  476. #
  477. def test_element_negation
  478. parse(%Q{<p></p><div></div>})
  479. select("*")
  480. assert_equal 2, @matches.size
  481. select("*:not(p)")
  482. assert_equal 1, @matches.size
  483. assert_equal "div", @matches[0].name
  484. select("*:not(div)")
  485. assert_equal 1, @matches.size
  486. assert_equal "p", @matches[0].name
  487. select("*:not(span)")
  488. assert_equal 2, @matches.size
  489. end
  490. def test_id_negation
  491. parse(%Q{<p id="1"></p><p id="2"></p>})
  492. select("p")
  493. assert_equal 2, @matches.size
  494. select(":not(#1)")
  495. assert_equal 1, @matches.size
  496. assert_equal "2", @matches[0].attributes["id"]
  497. select(":not(#2)")
  498. assert_equal 1, @matches.size
  499. assert_equal "1", @matches[0].attributes["id"]
  500. end
  501. def test_class_name_negation
  502. parse(%Q{<p class="foo"></p><p class="bar"></p>})
  503. select("p")
  504. assert_equal 2, @matches.size
  505. select(":not(.foo)")
  506. assert_equal 1, @matches.size
  507. assert_equal "bar", @matches[0].attributes["class"]
  508. select(":not(.bar)")
  509. assert_equal 1, @matches.size
  510. assert_equal "foo", @matches[0].attributes["class"]
  511. end
  512. def test_attribute_negation
  513. parse(%Q{<p title="foo"></p><p title="bar"></p>})
  514. select("p")
  515. assert_equal 2, @matches.size
  516. select(":not([title=foo])")
  517. assert_equal 1, @matches.size
  518. assert_equal "bar", @matches[0].attributes["title"]
  519. select(":not([title=bar])")
  520. assert_equal 1, @matches.size
  521. assert_equal "foo", @matches[0].attributes["title"]
  522. end
  523. def test_pseudo_class_negation
  524. parse(%Q{<div><p id="1"></p><p id="2"></p></div>})
  525. select("p")
  526. assert_equal 2, @matches.size
  527. select("p:not(:first-child)")
  528. assert_equal 1, @matches.size
  529. assert_equal "2", @matches[0].attributes["id"]
  530. select("p:not(:nth-child(2))")
  531. assert_equal 1, @matches.size
  532. assert_equal "1", @matches[0].attributes["id"]
  533. end
  534. def test_negation_details
  535. parse(%Q{<p id="1"></p><p id="2"></p><p id="3"></p>})
  536. assert_raise(ArgumentError) { select(":not(") }
  537. assert_raise(ArgumentError) { select(":not(:not())") }
  538. select("p:not(#1):not(#3)")
  539. assert_equal 1, @matches.size
  540. assert_equal "2", @matches[0].attributes["id"]
  541. end
  542. def test_select_from_element
  543. parse(%Q{<div><p id="1"></p><p id="2"></p></div>})
  544. select("div")
  545. @matches = @matches[0].select("p")
  546. assert_equal 2, @matches.size
  547. assert_equal "1", @matches[0].attributes["id"]
  548. assert_equal "2", @matches[1].attributes["id"]
  549. end
  550. protected
  551. def parse(html)
  552. @html = HTML::Document.new(html).root
  553. end
  554. def select(*selector)
  555. @matches = HTML.selector(*selector).select(@html)
  556. end
  557. end