Esempio n. 1
0
class TestElement(TestCase):
    def setUp(self):
        customElements.clear()
        self.elm = Element('tag')
        self.c1 = Element('c1')
        self.c2 = Element('c2')
        self.c1.classList.add('c1')
        self.c2.classList.add('c2')

    def tearDown(self):
        del self.elm
        del self.c1
        del self.c2
        super().tearDown()

    def test_constructor(self):
        elm = Element('a')
        self.assertEqual(elm.nodeName, 'A')
        self.assertEqual(elm.tagName, 'A')
        self.assertEqual(elm.localName, 'a')

        self.assertFalse(elm.hasChildNodes())
        self.assertFalse(elm.hasAttributes())

    def test_init_parent(self):
        elm = Element('a', parent=self.elm)
        self.assertIs(elm.parentNode, self.elm)

    def test_init_attrs(self):
        elm = Element('a', src='b', href='c')
        self.assertFalse(elm.hasChildNodes())
        self.assertTrue(elm.hasAttributes())
        self.assertTrue(elm.getAttribute('src'), 'b')
        self.assertTrue(elm.getAttribute('href'), 'c')

    def test_attrs(self):
        self.assertFalse(self.elm.hasAttributes())
        self.assertFalse(self.elm.hasAttribute('src'))
        self.assertNotIn('src', self.elm.attributes)
        self.assertIsNone(self.elm.getAttribute('src'))
        self.assertEqual(self.elm.html, '<tag></tag>')
        self.elm.setAttribute('src', 'a')
        self.assertTrue(self.elm.hasAttributes())
        self.assertTrue(self.elm.hasAttribute('src'))
        self.assertIn('src', self.elm.attributes)
        self.assertEqual(self.elm.getAttribute('src'), 'a')
        self.assertEqual(self.elm.html, '<tag src="a"></tag>')

        self.elm.removeAttribute('src')
        self.assertFalse(self.elm.hasAttributes())
        self.assertFalse(self.elm.hasAttribute('src'))
        self.assertNotIn('src', self.elm.attributes)
        self.assertIsNone(self.elm.getAttribute('src'))
        self.assertEqual(self.elm.html, '<tag></tag>')

    def test_id(self):
        self.assertEqual(self.elm.id, '')
        self.elm.setAttribute('id', 'a')
        self.assertEqual(self.elm.getAttribute('id'), 'a')
        self.assertEqual(self.elm.id, 'a')
        self.elm.id = 'b'
        self.assertEqual(self.elm.getAttribute('id'), 'b')
        self.assertEqual(self.elm.id, 'b')

    def test_class_list(self):
        self.assertIsNone(self.elm.getAttribute('class'))
        self.assertFalse(self.elm.hasAttribute('class'))
        self.assertFalse(self.elm.hasAttributes())

        self.elm.setAttribute('class', 'a')
        self.assertEqual(self.elm.getAttribute('class'), 'a')
        self.assertTrue(self.elm.hasAttribute('class'))
        self.assertTrue(self.elm.hasAttributes())

        self.elm.removeAttribute('class')
        self.assertIsNone(self.elm.getAttribute('class'))
        self.assertFalse(self.elm.hasAttribute('class'))
        self.assertFalse(self.elm.hasAttributes())

    def test_start_tag(self):
        self.assertEqual(self.elm.start_tag, '<tag>')
        self.elm.setAttribute('src', 'a')
        self.assertEqual(self.elm.start_tag, '<tag src="a">')

        self.elm.setAttribute('class', 'b')
        self.assertEqual(self.elm.start_tag, '<tag src="a" class="b">')

        self.elm.id = 'c'
        self.assertIn('src="a"', self.elm.start_tag)
        self.assertIn('id="c"', self.elm.start_tag)

    def test_inner_html(self):
        self.assertEqual(self.elm.innerHTML, '')
        self.elm.appendChild(Element('a'))
        self.assertEqual(self.elm.innerHTML, '<a></a>')

        self.elm.innerHTML = '<b></b>'
        self.assertEqual(self.elm.innerHTML, '<b></b>')
        self.assertEqual(self.elm.firstChild.tag, 'b')
        self.assertTrue(isinstance(self.elm.firstChild, HTMLElement))

    def test_inner_html_nest(self):
        html = '<b><c>d</c>e</b>'
        self.elm.innerHTML = html
        self.assertEqual(self.elm.innerHTML, html)
        self.assertEqual(self.elm.firstChild.html, html)
        self.assertEqual(self.elm.firstChild.firstChild.html, '<c>d</c>')
        self.assertEqual(self.elm.firstChild.firstChild.innerHTML, 'd')
        self.assertEqual(self.elm.firstChild.lastChild.html, 'e')
        self.assertTrue(isinstance(self.elm.firstChild.lastChild, Text))

    def test_parse_html_text(self):
        html = '''
        <a>a1</a1>
        b
        '''
        self.elm.innerHTML = html
        # fisrt node is empty (\n+spaces) text node
        self.assertEqual(self.elm.childNodes.length, 3)
        self.assertTrue(isinstance(self.elm.firstChild, Text))
        self.assertTrue(isinstance(self.elm.lastChild, Text))
        self.assertTrue(isinstance(self.elm.firstElementChild, HTMLElement))
        self.assertTrue(isinstance(self.elm.lastElementChild, HTMLElement))

    def test_insert_adjacent_html(self):
        self.elm.appendChild(self.c1)
        self.c1.insertAdjacentHTML('beforebegin', '<a></a>')
        self.assertEqual(self.elm.childNodes.length, 2)
        self.assertIs(self.elm.lastElementChild, self.c1)
        self.c1.insertAdjacentHTML('afterend', 'text')
        self.assertEqual(self.elm.childNodes.length, 3)
        self.assertIs(self.elm.lastElementChild, self.c1)
        self.c1.insertAdjacentHTML('afterBegin', '<b></b>')
        self.assertEqual(self.c1.childNodes.length, 1)
        self.c1.insertAdjacentHTML('BeforeEnd', '<c></c>')
        self.assertEqual(self.c1.childNodes.length, 2)
        with self.assertRaises(ValueError):
            self.c1.insertAdjacentHTML('a', 'b')

    def test_end_tag(self):
        self.assertEqual(self.elm.end_tag, '</tag>')

    def test_html(self):
        self.assertEqual(self.elm.html, '<tag></tag>')

    def test_append_string(self):
        with self.assertRaises(TypeError):
            self.elm.appendChild('a')
        self.assertFalse(self.elm.hasChildNodes())

    def test_get_elements_by_tagname(self):
        self.elm.appendChild(self.c1)
        self.elm.appendChild(self.c2)
        c1_tags = self.elm.getElementsByTagName('c1')
        c2_tags = self.elm.getElementsByTagName('c2')
        self.assertEqual(len(c1_tags), 1)
        self.assertEqual(len(c2_tags), 1)
        self.assertIs(c1_tags[0], self.c1)
        self.assertIs(c2_tags[0], self.c2)

    def test_get_elements_by_tagname_nest(self):
        self.elm.appendChild(self.c1)
        self.c1.appendChild(self.c2)
        c2_tags = self.c1.getElementsByTagName('c2')
        self.assertEqual(len(c2_tags), 1)
        self.assertIs(c2_tags[0], self.c2)
        c2_tags = self.elm.getElementsByTagName('c2')
        self.assertEqual(len(c2_tags), 1)
        self.assertIs(c2_tags[0], self.c2)

    def test_get_elements_by_tagname_self(self):
        c1_tags = self.c1.getElementsByTagName('c1')
        self.assertEqual(len(c1_tags), 0)

    def test_get_elements_by_classname(self):
        self.elm.appendChild(self.c1)
        self.elm.appendChild(self.c2)
        c1_classes = self.elm.getElementsByClassName('c1')
        c2_classes = self.elm.getElementsByClassName('c2')
        self.assertEqual(len(c1_classes), 1)
        self.assertEqual(len(c2_classes), 1)
        self.assertIs(c1_classes[0], self.c1)
        self.assertIs(c2_classes[0], self.c2)

    def test_get_elements_by_classname_nest(self):
        self.elm.appendChild(self.c1)
        self.c1.appendChild(self.c2)
        c2_classes = self.c1.getElementsByClassName('c2')
        self.assertEqual(len(c2_classes), 1)
        self.assertIs(c2_classes[0], self.c2)
        c2_classes = self.elm.getElementsByClassName('c2')
        self.assertEqual(len(c2_classes), 1)
        self.assertIs(c2_classes[0], self.c2)

    def test_clone_shallow_child(self):
        self.elm.appendChild(self.c1)
        clone = self.elm.cloneNode()
        self.assertFalse(clone.hasChildNodes())

        clone.appendChild(self.c2)
        self.assertFalse(self.c2 in self.elm)
        self.assertEqual(len(self.elm.childNodes), 1)

    def test_clone_shallow_attr(self):
        self.elm.setAttribute('src', 'a')
        clone = self.elm.cloneNode()

        self.assertTrue(clone.hasAttribute('src'))
        self.assertTrue(clone.getAttribute('src'), 'a')
        self.assertEqual(self.elm.attributes.toString(),
                         clone.attributes.toString())
        clone.setAttribute('src', 'b')
        self.assertNotEqual(self.elm.attributes.toString(),
                            clone.attributes.toString())
        self.assertTrue(self.elm.getAttribute('src'), 'a')
        self.assertTrue(clone.getAttribute('src'), 'b')

    def test_clone_deep_child(self):
        self.elm.appendChild(self.c1)
        clone = self.elm.cloneNode(deep=True)
        self.assertTrue(clone.hasChildNodes())
        self.assertEqual(len(clone.childNodes), 1)
        self.assertTrue(self.c1 in self.elm)
        self.assertFalse(self.c1 in clone)
        self.assertIsNot(self.c1, clone.firstChild)

        clone.appendChild(self.c2)
        self.assertFalse(self.c2 in self.elm)
        self.assertEqual(len(self.elm.childNodes), 1)
        self.assertEqual(len(clone.childNodes), 2)

    def test_clone_deep_attr(self):
        self.elm.setAttribute('src', 'a')
        self.elm.appendChild(self.c1)
        self.c1.setAttribute('src', 'c1')
        clone = self.elm.cloneNode(deep=True)

        self.assertTrue(clone.hasAttribute('src'))
        self.assertTrue(clone.getAttribute('src'), 'a')
        self.assertTrue(clone.firstChild.hasAttribute('src'))
        self.assertTrue(clone.firstChild.getAttribute('src'), 'c1')
        self.assertEqual(self.elm.attributes.toString(),
                         clone.attributes.toString())
        self.assertEqual(self.c1.attributes.toString(),
                         clone.firstChild.attributes.toString())

        clone.firstChild.setAttribute('src', 'b')
        self.assertNotEqual(self.c1.attributes.toString(),
                            clone.firstChild.attributes.toString())
        self.assertTrue(self.c1.getAttribute('src'), 'a')
        self.assertTrue(clone.firstChild.getAttribute('src'), 'b')

    def test_init_class(self):
        elm = Element('a', class_='a')
        self.assertEqual(elm.html, '<a class="a"></a>')
        self.assertEqual(elm.classList.length, 1)
        self.assertIn('a', elm.classList)

        elm2 = Element('a', **{'class': 'b'})
        self.assertEqual(elm2.html, '<a class="b"></a>')
        self.assertEqual(elm2.classList.length, 1)
        self.assertIn('b', elm2.classList)

    def test_init_class_multi_str(self):
        elm = Element('a', class_='a1 a2')
        self.assertEqual(elm.html, '<a class="a1 a2"></a>')
        self.assertEqual(elm.classList.length, 2)
        self.assertIn('a1', elm.classList)
        self.assertIn('a2', elm.classList)
        self.assertNotIn('a1 a2', elm.classList)

    def test_init_class_multi_list(self):
        elm = Element('a', class_=['a1', 'a2'])
        self.assertEqual(elm.html, '<a class="a1 a2"></a>')
        self.assertEqual(elm.classList.length, 2)
        self.assertIn('a1', elm.classList)
        self.assertIn('a2', elm.classList)
        self.assertNotIn('a1 a2', elm.classList)

    def test_init_class_multi_mixed(self):
        elm = Element('a', class_=['a1', 'a2 a3'])
        self.assertEqual(elm.html, '<a class="a1 a2 a3"></a>')
        self.assertEqual(elm.classList.length, 3)
        self.assertIn('a1', elm.classList)
        self.assertIn('a2', elm.classList)
        self.assertIn('a3', elm.classList)
        self.assertNotIn('a2 a3', elm.classList)

    def test_reference(self):
        gc.collect()
        elm = Element('a')
        _id = id(elm)
        self.assertIn(elm, Element._elements)
        del elm
        gc.collect()  # run gc
        for elm in Element._elements:
            assert id(elm) != _id

    def test_reference_with_id(self):
        gc.collect()
        elm = Element('a', id='a')
        _id = id(elm)
        self.assertIn(elm.id, Element._elements_with_id)
        del elm
        gc.collect()
        self.assertNotIn('a', Element._elements_with_id)
        for elm in Element._elements:
            assert id(elm) != _id

    def test_reference_add_id(self):
        gc.collect()
        elm = Element('a')
        _id = id(elm)
        self.assertNotIn(elm, Element._elements_with_id.values())
        elm.id = 'a'
        self.assertIn('a', Element._elements_with_id)
        self.assertIn(elm, Element._elements_with_id.values())
        elm.id = 'b'
        self.assertNotIn('a', Element._elements_with_id)
        self.assertIn('b', Element._elements_with_id)
        self.assertIn(elm, Element._elements_with_id.values())
        elm.setAttribute('id', 'c')
        self.assertNotIn('b', Element._elements_with_id)
        self.assertIn('c', Element._elements_with_id)
        self.assertIn(elm, Element._elements_with_id.values())
        del elm
        gc.collect()
        self.assertNotIn('c', Element._elements_with_id)
        for elm in Element._elements:
            assert id(elm) != _id

    def test_reference_del_id(self):
        gc.collect()
        elm = Element('a', id='a')
        self.assertIn('a', Element._elements_with_id)
        self.assertIn(elm, Element._elements_with_id.values())
        elm.removeAttribute('id')
        self.assertNotIn('a', Element._elements_with_id)
        self.assertNotIn(elm, Element._elements_with_id.values())

    def test_is_attr(self):
        '''``is`` is a reserved word for python, so use ``is_`` in constructor.
        '''
        elm = Element('tag', is_='elm')
        self.assertIn('is', elm.attributes)
        self.assertNotIn('is_', elm.attributes)
        self.assertEqual('elm', elm.getAttribute('is'))
        self.assertIsNone(elm.getAttribute('is_'))

        # ``is_`` is not treated as special at setAttribute
        elm.setAttribute('is_', 'new')
        self.assertEqual('elm', elm.getAttribute('is'))
        self.assertEqual('new', elm.getAttribute('is_'))

    class NewTag(HTMLElement):
        pass

    def test_custom_tag(self):
        self.elm.innerHTML = '<new-tag></new-tag>'
        child = self.elm.firstChild
        self.assertEqual(child.__class__, HTMLElement)
        customElements.define('new-tag', self.NewTag)
        self.assertEqual(child.__class__, self.NewTag)

    def test_custom_tag_registered(self):
        customElements.define('new-tag', self.NewTag)
        self.elm.innerHTML = '<new-tag></new-tag>'
        self.assertEqual(self.elm.firstChild.__class__, self.NewTag)

    def test_custom_tag_is(self):
        self.elm.innerHTML = '<a is="my-a"></a>'
        child = self.elm.firstChild
        self.assertEqual(child.__class__, HTMLElement)
        self.assertEqual(child.getAttribute('is'), 'my-a')
        customElements.define('my-a', self.NewTag, {'extends': 'a'})
        self.assertEqual(self.elm.firstChild.__class__, self.NewTag)

    def test_custom_tag_is_registered(self):
        customElements.define('my-a', self.NewTag, {'extends': 'a'})
        self.elm.innerHTML = '<a is="my-a"></a>'
        self.assertEqual(self.elm.firstChild.__class__, self.NewTag)

    def test_invalid_define_args(self):
        with self.assertRaises(TypeError):
            customElements.define(1, 2, 3)
Esempio n. 2
0
class TestElement(TestCase):
    def setUp(self):
        customElements.clear()
        self.elm = Element('tag')
        self.c1 = Element('c1')
        self.c2 = Element('c2')
        self.c1.classList.add('c1')
        self.c2.classList.add('c2')

    def tearDown(self):
        del self.elm
        del self.c1
        del self.c2
        super().tearDown()

    def test_constructor(self):
        elm = Element('a')
        self.assertEqual(elm.nodeName, 'A')
        self.assertEqual(elm.tagName, 'A')
        self.assertEqual(elm.localName, 'a')

        self.assertFalse(elm.hasChildNodes())
        self.assertFalse(elm.hasAttributes())

    def test_init_parent(self):
        elm = Element('a', parent=self.elm)
        self.assertIs(elm.parentNode, self.elm)

    def test_init_attrs(self):
        elm = Element('a', src='b', href='c')
        self.assertFalse(elm.hasChildNodes())
        self.assertTrue(elm.hasAttributes())
        self.assertTrue(elm.getAttribute('src'), 'b')
        self.assertTrue(elm.getAttribute('href'), 'c')

    def test_attrs(self):
        self.assertFalse(self.elm.hasAttributes())
        self.assertFalse(self.elm.hasAttribute('src'))
        self.assertNotIn('src', self.elm.attributes)
        self.assertIsNone(self.elm.getAttribute('src'))
        self.assertEqual(self.elm.html, '<tag></tag>')
        self.elm.setAttribute('src', 'a')
        self.assertTrue(self.elm.hasAttributes())
        self.assertTrue(self.elm.hasAttribute('src'))
        self.assertIn('src', self.elm.attributes)
        self.assertEqual(self.elm.getAttribute('src'), 'a')
        self.assertEqual(self.elm.html, '<tag src="a"></tag>')

        self.elm.removeAttribute('src')
        self.assertFalse(self.elm.hasAttributes())
        self.assertFalse(self.elm.hasAttribute('src'))
        self.assertNotIn('src', self.elm.attributes)
        self.assertIsNone(self.elm.getAttribute('src'))
        self.assertEqual(self.elm.html, '<tag></tag>')

    def test_id(self):
        self.assertEqual(self.elm.id, '')
        self.elm.setAttribute('id', 'a')
        self.assertEqual(self.elm.getAttribute('id'), 'a')
        self.assertEqual(self.elm.id, 'a')
        self.elm.id = 'b'
        self.assertEqual(self.elm.getAttribute('id'), 'b')
        self.assertEqual(self.elm.id, 'b')

    def test_class_list_str(self):
        self.assertIsNone(self.elm.getAttribute('class'))
        self.assertFalse(self.elm.hasAttribute('class'))
        self.assertFalse(self.elm.hasAttributes())

        self.elm.setAttribute('class', 'a')
        self.assertEqual(self.elm.getAttribute('class'), 'a')
        self.assertTrue(self.elm.hasAttribute('class'))
        self.assertTrue(self.elm.hasAttributes())

        self.elm.removeAttribute('class')
        self.assertIsNone(self.elm.getAttribute('class'))
        self.assertFalse(self.elm.hasAttribute('class'))
        self.assertFalse(self.elm.hasAttributes())

    def test_class_list_list(self):
        self.elm.setAttribute('class', ['a', 'b'])
        self.assertEqual(self.elm.getAttribute('class'), 'a b')
        self.assertTrue(self.elm.hasAttribute('class'))
        self.assertTrue(self.elm.hasAttributes())

    def test_class_name(self):
        self.assertEqual(self.elm.className, '')
        self.elm.className = 'a'
        self.assertEqual(self.elm.className, 'a')
        self.assertEqual(self.elm.getAttribute('class'), 'a')
        self.elm.className = 'b c'
        self.assertEqual(self.elm.className, 'b c')
        self.assertEqual(self.elm.getAttribute('class'), 'b c')
        self.assertEqual(self.elm.classList.length, 2)
        self.elm.className = 'd'
        self.assertEqual(self.elm.className, 'd')
        self.assertEqual(self.elm.getAttribute('class'), 'd')
        self.assertEqual(self.elm.classList.length, 1)
        with self.assertRaises(TypeError):
            self.elm.className = ['d']

    def test_start_tag(self):
        self.assertEqual(self.elm.start_tag, '<tag>')
        self.elm.setAttribute('src', 'a')
        self.assertEqual(self.elm.start_tag, '<tag src="a">')

        self.elm.setAttribute('class', 'b')
        self.assertEqual(self.elm.start_tag, '<tag src="a" class="b">')

        self.elm.id = 'c'
        self.assertIn('src="a"', self.elm.start_tag)
        self.assertIn('id="c"', self.elm.start_tag)

    def test_inner_html(self):
        self.assertEqual(self.elm.innerHTML, '')
        self.elm.appendChild(Element('a'))
        self.assertEqual(self.elm.innerHTML, '<a></a>')

        self.elm.innerHTML = '<b></b>'
        self.assertEqual(self.elm.innerHTML, '<b></b>')
        self.assertEqual(self.elm.firstChild.tag, 'b')
        self.assertTrue(isinstance(self.elm.firstChild, Element))

    def test_inner_html_nest(self):
        html = '<b><c>d</c>e</b>'
        self.elm.innerHTML = html
        self.assertEqual(self.elm.innerHTML, html)
        self.assertEqual(self.elm.firstChild.html, html)
        self.assertEqual(self.elm.firstChild.firstChild.html, '<c>d</c>')
        self.assertEqual(self.elm.firstChild.firstChild.innerHTML, 'd')
        self.assertEqual(self.elm.firstChild.lastChild.html, 'e')
        self.assertTrue(isinstance(self.elm.firstChild.lastChild, Text))

    def test_parse_html_text(self):
        html = '''
        <a>a1</a1>
        b
        '''
        self.elm.innerHTML = html
        # fisrt node is empty (\n+spaces) text node
        self.assertEqual(self.elm.childNodes.length, 3)
        self.assertTrue(isinstance(self.elm.firstChild, Text))
        self.assertTrue(isinstance(self.elm.lastChild, Text))
        self.assertTrue(isinstance(self.elm.firstElementChild, Element))
        self.assertTrue(isinstance(self.elm.lastElementChild, Element))

    def test_insert_adjacent_html(self):
        self.elm.appendChild(self.c1)
        self.c1.insertAdjacentHTML('beforebegin', '<a></a>')
        self.assertEqual(self.elm.childNodes.length, 2)
        self.assertIs(self.elm.lastElementChild, self.c1)
        self.c1.insertAdjacentHTML('afterend', 'text')
        self.assertEqual(self.elm.childNodes.length, 3)
        self.assertIs(self.elm.lastElementChild, self.c1)
        self.c1.insertAdjacentHTML('afterBegin', '<b></b>')
        self.assertEqual(self.c1.childNodes.length, 1)
        self.c1.insertAdjacentHTML('BeforeEnd', '<c></c>')
        self.assertEqual(self.c1.childNodes.length, 2)
        with self.assertRaises(ValueError):
            self.c1.insertAdjacentHTML('a', 'b')

    def test_end_tag(self):
        self.assertEqual(self.elm.end_tag, '</tag>')

    def test_html(self):
        self.assertEqual(self.elm.html, '<tag></tag>')

    def test_append_string(self):
        with self.assertRaises(TypeError):
            self.elm.appendChild('a')
        self.assertFalse(self.elm.hasChildNodes())

    def test_get_elements_by_tagname(self):
        self.elm.appendChild(self.c1)
        self.elm.appendChild(self.c2)
        c1_tags = self.elm.getElementsByTagName('c1')
        c2_tags = self.elm.getElementsByTagName('c2')
        self.assertEqual(len(c1_tags), 1)
        self.assertEqual(len(c2_tags), 1)
        self.assertIs(c1_tags[0], self.c1)
        self.assertIs(c2_tags[0], self.c2)

    def test_get_elements_by_tagname_nest(self):
        self.elm.appendChild(self.c1)
        self.c1.appendChild(self.c2)
        c2_tags = self.c1.getElementsByTagName('c2')
        self.assertEqual(len(c2_tags), 1)
        self.assertIs(c2_tags[0], self.c2)
        c2_tags = self.elm.getElementsByTagName('c2')
        self.assertEqual(len(c2_tags), 1)
        self.assertIs(c2_tags[0], self.c2)

    def test_get_elements_by_tagname_self(self):
        c1_tags = self.c1.getElementsByTagName('c1')
        self.assertEqual(len(c1_tags), 0)

    def test_get_elements_by_classname(self):
        self.elm.appendChild(self.c1)
        self.elm.appendChild(self.c2)
        c1_classes = self.elm.getElementsByClassName('c1')
        c2_classes = self.elm.getElementsByClassName('c2')
        self.assertEqual(len(c1_classes), 1)
        self.assertEqual(len(c2_classes), 1)
        self.assertIs(c1_classes[0], self.c1)
        self.assertIs(c2_classes[0], self.c2)

    def test_get_elements_by_classname_multi1(self):
        self.elm.appendChild(self.c1)
        self.elm.appendChild(self.c2)
        self.c2.classList.add('c1')
        c1_classes = self.elm.getElementsByClassName('c1')
        c2_classes = self.elm.getElementsByClassName('c2')
        self.assertEqual(len(c1_classes), 2)
        self.assertEqual(len(c2_classes), 1)

    def test_get_elements_by_classname_multi2(self):
        self.elm.appendChild(self.c1)
        self.elm.appendChild(self.c2)
        self.c1.classList.add('c3')
        self.c2.classList.add('c1')
        self.c2.classList.add('c3')
        classes1 = self.elm.getElementsByClassName('c1')
        classes2 = self.elm.getElementsByClassName('c1 c2')
        classes3 = self.elm.getElementsByClassName('c1 c2 c4')
        self.assertEqual(len(classes1), 2)
        self.assertEqual(len(classes2), 1)
        self.assertEqual(len(classes3), 0)
        self.assertIs(classes2[0], self.c2)

    def test_get_elements_by_classname_nest(self):
        self.elm.appendChild(self.c1)
        self.c1.appendChild(self.c2)
        c2_classes = self.c1.getElementsByClassName('c2')
        self.assertEqual(len(c2_classes), 1)
        self.assertIs(c2_classes[0], self.c2)
        c2_classes = self.elm.getElementsByClassName('c2')
        self.assertEqual(len(c2_classes), 1)
        self.assertIs(c2_classes[0], self.c2)

    def test_clone_shallow_child(self):
        self.elm.appendChild(self.c1)
        clone = self.elm.cloneNode()
        self.assertFalse(clone.hasChildNodes())

        clone.appendChild(self.c2)
        self.assertFalse(self.c2 in self.elm)
        self.assertEqual(len(self.elm.childNodes), 1)

    def test_clone_shallow_attr(self):
        self.elm.setAttribute('src', 'a')
        clone = self.elm.cloneNode()

        self.assertTrue(clone.hasAttribute('src'))
        self.assertTrue(clone.getAttribute('src'), 'a')
        self.assertEqual(self.elm.attributes.toString(),
                         clone.attributes.toString())
        clone.setAttribute('src', 'b')
        self.assertNotEqual(self.elm.attributes.toString(),
                            clone.attributes.toString())
        self.assertTrue(self.elm.getAttribute('src'), 'a')
        self.assertTrue(clone.getAttribute('src'), 'b')

    def test_clone_deep_child(self):
        self.elm.appendChild(self.c1)
        clone = self.elm.cloneNode(deep=True)
        self.assertTrue(clone.hasChildNodes())
        self.assertEqual(len(clone.childNodes), 1)
        self.assertTrue(self.c1 in self.elm)
        self.assertFalse(self.c1 in clone)
        self.assertIsNot(self.c1, clone.firstChild)

        clone.appendChild(self.c2)
        self.assertFalse(self.c2 in self.elm)
        self.assertEqual(len(self.elm.childNodes), 1)
        self.assertEqual(len(clone.childNodes), 2)

    def test_clone_deep_attr(self):
        self.elm.setAttribute('src', 'a')
        self.elm.appendChild(self.c1)
        self.c1.setAttribute('src', 'c1')
        clone = self.elm.cloneNode(deep=True)

        self.assertTrue(clone.hasAttribute('src'))
        self.assertTrue(clone.getAttribute('src'), 'a')
        self.assertTrue(clone.firstChild.hasAttribute('src'))
        self.assertTrue(clone.firstChild.getAttribute('src'), 'c1')
        self.assertEqual(self.elm.attributes.toString(),
                         clone.attributes.toString())
        self.assertEqual(self.c1.attributes.toString(),
                         clone.firstChild.attributes.toString())

        clone.firstChild.setAttribute('src', 'b')
        self.assertNotEqual(self.c1.attributes.toString(),
                            clone.firstChild.attributes.toString())
        self.assertTrue(self.c1.getAttribute('src'), 'a')
        self.assertTrue(clone.firstChild.getAttribute('src'), 'b')

    def test_clone_style(self):
        self.elm.setAttribute('style', 'color: red;')
        clone = self.elm.cloneNode()
        self.assertEqual(clone.html, self.elm.html)

    def test_init_class(self):
        elm = Element('a', class_='a')
        self.assertEqual(elm.html, '<a class="a"></a>')
        self.assertEqual(elm.classList.length, 1)
        self.assertIn('a', elm.classList)

        elm2 = Element('a', **{'class': 'b'})
        self.assertEqual(elm2.html, '<a class="b"></a>')
        self.assertEqual(elm2.classList.length, 1)
        self.assertIn('b', elm2.classList)

    def test_init_class_multi_str(self):
        elm = Element('a', class_='a1 a2')
        self.assertEqual(elm.html, '<a class="a1 a2"></a>')
        self.assertEqual(elm.classList.length, 2)
        self.assertIn('a1', elm.classList)
        self.assertIn('a2', elm.classList)
        self.assertNotIn('a1 a2', elm.classList)

    def test_init_class_multi_list(self):
        elm = Element('a', class_=['a1', 'a2'])
        self.assertEqual(elm.html, '<a class="a1 a2"></a>')
        self.assertEqual(elm.classList.length, 2)
        self.assertIn('a1', elm.classList)
        self.assertIn('a2', elm.classList)
        self.assertNotIn('a1 a2', elm.classList)

    def test_init_class_multi_mixed(self):
        elm = Element('a', class_=['a1', 'a2 a3'])
        self.assertEqual(elm.html, '<a class="a1 a2 a3"></a>')
        self.assertEqual(elm.classList.length, 3)
        self.assertIn('a1', elm.classList)
        self.assertIn('a2', elm.classList)
        self.assertIn('a3', elm.classList)
        self.assertNotIn('a2 a3', elm.classList)

    def test_reference(self):
        gc.collect()
        elm = Element('a')
        _id = id(elm)
        self.assertIn(elm, Element._element_buffer)
        del elm
        gc.collect()  # run gc
        for elm in Element._element_buffer:
            assert id(elm) != _id

    def test_reference_with_id(self):
        gc.collect()
        elm = Element('a', id='a')
        _id = id(elm)
        self.assertIn(elm.id, Element._elements_with_id)
        del elm
        gc.collect()
        self.assertNotIn('a', Element._elements_with_id)
        for elm in Element._element_buffer:
            assert id(elm) != _id

    @skipIf(sys.implementation.name == 'pypy', 'GC not work in PyPy.')
    def test_reference_add_id(self):
        gc.collect()
        elm = Element('a')
        _id = id(elm)
        self.assertNotIn(elm, Element._elements_with_id.values())
        elm.id = 'a'
        self.assertIn('a', Element._elements_with_id)
        self.assertIn(elm, Element._elements_with_id.values())
        elm.id = 'b'
        self.assertNotIn('a', Element._elements_with_id)
        self.assertIn('b', Element._elements_with_id)
        self.assertIn(elm, Element._elements_with_id.values())
        elm.setAttribute('id', 'c')
        self.assertNotIn('b', Element._elements_with_id)
        self.assertIn('c', Element._elements_with_id)
        self.assertIn(elm, Element._elements_with_id.values())
        del elm
        gc.collect()
        self.assertNotIn('c', Element._elements_with_id)
        for elm in Element._element_buffer:
            assert id(elm) != _id

    def test_reference_del_id(self):
        gc.collect()
        elm = Element('a', id='a')
        self.assertIn('a', Element._elements_with_id)
        self.assertIn(elm, Element._elements_with_id.values())
        elm.removeAttribute('id')
        self.assertNotIn('a', Element._elements_with_id)
        self.assertNotIn(elm, Element._elements_with_id.values())

    def test_is_attr(self):
        '''``is`` is a reserved word for python, so use ``is_`` in constructor.
        '''
        elm = Element('tag', is_='elm')
        self.assertIn('is', elm.attributes)
        self.assertNotIn('is_', elm.attributes)
        self.assertEqual('elm', elm.getAttribute('is'))
        self.assertIsNone(elm.getAttribute('is_'))

        # ``is_`` is not treated as special at setAttribute
        elm.setAttribute('is_', 'new')
        self.assertEqual('elm', elm.getAttribute('is'))
        self.assertEqual('new', elm.getAttribute('is_'))

    class NewTag(HTMLElement):
        pass

    def test_custom_tag(self):
        self.elm.innerHTML = '<new-tag></new-tag>'
        child = self.elm.firstChild
        self.assertEqual(child.__class__, Element)
        customElements.define('new-tag', self.NewTag)
        self.assertEqual(child.__class__, self.NewTag)

    def test_custom_tag_registered(self):
        customElements.define('new-tag', self.NewTag)
        self.elm.innerHTML = '<new-tag></new-tag>'
        self.assertEqual(self.elm.firstChild.__class__, self.NewTag)

    def test_custom_tag_is(self):
        self.elm.innerHTML = '<a is="my-a"></a>'
        child = self.elm.firstChild
        self.assertEqual(child.__class__, Element)
        self.assertEqual(child.getAttribute('is'), 'my-a')
        customElements.define('my-a', self.NewTag, {'extends': 'a'})
        self.assertEqual(self.elm.firstChild.__class__, self.NewTag)

    def test_custom_tag_is_registered(self):
        customElements.define('my-a', self.NewTag, {'extends': 'a'})
        self.elm.innerHTML = '<a is="my-a"></a>'
        self.assertEqual(self.elm.firstChild.__class__, self.NewTag)

    def test_invalid_define_args(self):
        with self.assertRaises(TypeError):
            customElements.define(1, 2, 3)