""" Selector tests for cssselect backend """ import unittest from parsel.csstranslator import GenericTranslator, HTMLTranslator from parsel import Selector from cssselect.parser import SelectorSyntaxError from cssselect.xpath import ExpressionError HTMLBODY = u'''
link

lorem ipsum text hi there guy

''' class TranslatorTestMixin: def setUp(self): self.tr = self.tr_cls() self.c2x = self.tr.css_to_xpath def test_attr_function(self): cases = [ ('::attr(name)', u'descendant-or-self::*/@name'), ('a::attr(href)', u'descendant-or-self::a/@href'), ('a ::attr(img)', u'descendant-or-self::a/descendant-or-self::*/@img'), ('a > ::attr(class)', u'descendant-or-self::a/*/@class'), ] for css, xpath in cases: self.assertEqual(self.c2x(css), xpath, css) def test_attr_function_exception(self): cases = [ ('::attr(12)', ExpressionError), ('::attr(34test)', ExpressionError), ('::attr(@href)', SelectorSyntaxError), ] for css, exc in cases: self.assertRaises(exc, self.c2x, css) def test_text_pseudo_element(self): cases = [ ('::text', u'descendant-or-self::text()'), ('p::text', u'descendant-or-self::p/text()'), ('p ::text', u'descendant-or-self::p/descendant-or-self::text()'), ('#id::text', u"descendant-or-self::*[@id = 'id']/text()"), ('p#id::text', u"descendant-or-self::p[@id = 'id']/text()"), ('p#id ::text', u"descendant-or-self::p[@id = 'id']/descendant-or-self::text()"), ('p#id > ::text', u"descendant-or-self::p[@id = 'id']/*/text()"), ('p#id ~ ::text', u"descendant-or-self::p[@id = 'id']/following-sibling::*/text()"), ('a[href]::text', u'descendant-or-self::a[@href]/text()'), ('a[href] ::text', u'descendant-or-self::a[@href]/descendant-or-self::text()'), ('p::text, a::text', u"descendant-or-self::p/text() | descendant-or-self::a/text()"), ] for css, xpath in cases: self.assertEqual(self.c2x(css), xpath, css) def test_pseudo_function_exception(self): cases = [ ('::attribute(12)', ExpressionError), ('::text()', ExpressionError), ('::attr(@href)', SelectorSyntaxError), ] for css, exc in cases: self.assertRaises(exc, self.c2x, css) def test_unknown_pseudo_element(self): cases = [ ('::text-node', ExpressionError), ] for css, exc in cases: self.assertRaises(exc, self.c2x, css) def test_unknown_pseudo_class(self): cases = [ (':text', ExpressionError), (':attribute(name)', ExpressionError), ] for css, exc in cases: self.assertRaises(exc, self.c2x, css) class HTMLTranslatorTest(TranslatorTestMixin, unittest.TestCase): tr_cls = HTMLTranslator class GenericTranslatorTest(TranslatorTestMixin, unittest.TestCase): tr_cls = GenericTranslator class UtilCss2XPathTest(unittest.TestCase): def test_css2xpath(self): from parsel import css2xpath expected_xpath = (u"descendant-or-self::*[@class and contains(" "concat(' ', normalize-space(@class), ' '), ' some-class ')]") self.assertEqual(css2xpath('.some-class'), expected_xpath) class CSSSelectorTest(unittest.TestCase): sscls = Selector def setUp(self): self.sel = self.sscls(text=HTMLBODY) def x(self, *a, **kw): return [v.strip() for v in self.sel.css(*a, **kw).extract() if v.strip()] def test_selector_simple(self): for x in self.sel.css('input'): self.assertTrue(isinstance(x, self.sel.__class__), x) self.assertEqual(self.sel.css('input').extract(), [x.extract() for x in self.sel.css('input')]) def test_text_pseudo_element(self): self.assertEqual(self.x('#p-b2'), [u'guy']) self.assertEqual(self.x('#p-b2::text'), [u'guy']) self.assertEqual(self.x('#p-b2 ::text'), [u'guy']) self.assertEqual(self.x('#paragraph::text'), [u'lorem ipsum text']) self.assertEqual(self.x('#paragraph ::text'), [u'lorem ipsum text', u'hi', u'there', u'guy']) self.assertEqual(self.x('p::text'), [u'lorem ipsum text']) self.assertEqual(self.x('p ::text'), [u'lorem ipsum text', u'hi', u'there', u'guy']) def test_attribute_function(self): self.assertEqual(self.x('#p-b2::attr(id)'), [u'p-b2']) self.assertEqual(self.x('.cool-footer::attr(class)'), [u'cool-footer']) self.assertEqual(self.x('.cool-footer ::attr(id)'), [u'foobar-div', u'foobar-span']) self.assertEqual(self.x('map[name="dummymap"] ::attr(shape)'), [u'circle', u'default']) def test_nested_selector(self): self.assertEqual(self.sel.css('p').css('b::text').extract(), [u'hi', u'guy']) self.assertEqual(self.sel.css('div').css('area:last-child').extract(), [u''])