2,282 bytes · last changed 2026-10-25 in Initial public release
| 1 | import pytest |
| 2 | |
| 3 | from pyrtan.html import SelectorError, compile_selector, parse |
| 4 | |
| 5 | DOC = """ |
| 6 | <html><head><title>Shop</title></head> |
| 7 | <body> |
| 8 | <div id="main" class="wrap big"> |
| 9 | <h1>Items</h1> |
| 10 | <table> |
| 11 | <tr class="row"><td>Apple</td><td class="qty">3</td></tr> |
| 12 | <tr class="row sold-out"><td>Pear</td><td class="qty">0</td></tr> |
| 13 | </table> |
| 14 | <a href="/one" class="story">One</a> |
| 15 | <a href="https://x/two" class="story external">Two & more</a> |
| 16 | <p>Total: <b>2</b> items<br>end</p> |
| 17 | </div> |
| 18 | </body></html> |
| 19 | """ |
| 20 | |
| 21 | |
| 22 | @pytest.fixture |
| 23 | def doc(): |
| 24 | return parse(DOC) |
| 25 | |
| 26 | |
| 27 | def test_tag_id_class(doc): |
| 28 | assert doc.select_one("title").text == "Shop" |
| 29 | assert doc.select_one("#main").tag == "div" |
| 30 | assert [e.text for e in doc.select(".row")] == ["Apple 3", "Pear 0"] |
| 31 | assert len(doc.select(".row.sold-out")) == 1 |
| 32 | assert doc.select_one("div.wrap h1").text == "Items" |
| 33 | |
| 34 | |
| 35 | def test_attribute_selectors(doc): |
| 36 | assert [a.get("href") for a in doc.select("a[href]")] == ["/one", "https://x/two"] |
| 37 | assert doc.select_one('a[href="/one"]').text == "One" |
| 38 | assert doc.select_one("a[href^=https]").text == "Two & more" |
| 39 | assert doc.select_one("a[href$=two]").text == "Two & more" |
| 40 | assert doc.select_one("a[class*=external]").get("href") == "https://x/two" |
| 41 | |
| 42 | |
| 43 | def test_combinators_and_pseudo(doc): |
| 44 | assert [e.text for e in doc.select("tr > td:nth-child(2)")] == ["3", "0"] |
| 45 | assert doc.select_one("tr:first-child td").text == "Apple" |
| 46 | assert doc.select_one("tr:last-child td").text == "Pear" |
| 47 | assert doc.select_one("td:contains(Pear)").text == "Pear" |
| 48 | assert [e.tag for e in doc.select("h1, title")] == ["title", "h1"] |
| 49 | assert doc.select("#main > td") == [] |
| 50 | assert len(doc.select("#main td")) == 4 |
| 51 | |
| 52 | |
| 53 | def test_text_collapses_whitespace_and_void_tags(doc): |
| 54 | assert doc.select_one("p").text == "Total: 2 items end" |
| 55 | |
| 56 | |
| 57 | def test_unsupported_selector_is_an_error(): |
| 58 | with pytest.raises(SelectorError): |
| 59 | compile_selector("a ~ b") |
| 60 | with pytest.raises(SelectorError): |
| 61 | compile_selector("div:hover") |
| 62 | with pytest.raises(SelectorError): |
| 63 | compile_selector("") |
| 64 | |
| 65 | |
| 66 | def test_malformed_html_does_not_raise(): |
| 67 | doc = parse("<div><p>unclosed<div>another</p></div>") |
| 68 | assert doc.select_one("div").text.startswith("unclosed") |