1# This Source Code Form is subject to the terms of the Mozilla Public
2# License, v. 2.0. If a copy of the MPL was not distributed with this
3# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5from __future__ import absolute_import, print_function
6
7import types
8
9import six
10from six.moves.urllib.parse import quote
11
12from marionette_driver.by import By
13from marionette_harness import MarionetteTestCase
14
15
16boolean_attributes = {
17    "audio": ["autoplay", "controls", "loop", "muted"],
18    "button": ["autofocus", "disabled", "formnovalidate"],
19    "details": ["open"],
20    "dialog": ["open"],
21    "fieldset": ["disabled"],
22    "form": ["novalidate"],
23    "iframe": ["allowfullscreen"],
24    "img": ["ismap"],
25    "input": [
26        "autofocus",
27        "checked",
28        "disabled",
29        "formnovalidate",
30        "multiple",
31        "readonly",
32        "required",
33    ],
34    "menuitem": ["checked", "default", "disabled"],
35    "ol": ["reversed"],
36    "optgroup": ["disabled"],
37    "option": ["disabled", "selected"],
38    "script": ["async", "defer"],
39    "select": ["autofocus", "disabled", "multiple", "required"],
40    "textarea": ["autofocus", "disabled", "readonly", "required"],
41    "track": ["default"],
42    "video": ["autoplay", "controls", "loop", "muted"],
43}
44
45
46def inline(doc, doctype="html"):
47    if doctype == "html":
48        return "data:text/html;charset=utf-8,{}".format(quote(doc))
49    elif doctype == "xhtml":
50        return "data:application/xhtml+xml,{}".format(
51            quote(
52                r"""<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
53    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
54<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
55  <head>
56    <title>XHTML might be the future</title>
57  </head>
58
59  <body>
60    {}
61  </body>
62</html>""".format(
63                    doc
64                )
65            )
66        )
67
68
69attribute = inline("<input foo=bar>")
70input = inline("<input>")
71disabled = inline("<input disabled=baz>")
72check = inline("<input type=checkbox>")
73
74
75class TestIsElementEnabled(MarionetteTestCase):
76    def test_is_enabled(self):
77        test_html = self.marionette.absolute_url("test.html")
78        self.marionette.navigate(test_html)
79        l = self.marionette.find_element(By.NAME, "myCheckBox")
80        self.assertTrue(l.is_enabled())
81        self.marionette.execute_script("arguments[0].disabled = true;", [l])
82        self.assertFalse(l.is_enabled())
83
84
85class TestIsElementDisplayed(MarionetteTestCase):
86    def test_is_displayed(self):
87        test_html = self.marionette.absolute_url("test.html")
88        self.marionette.navigate(test_html)
89        l = self.marionette.find_element(By.NAME, "myCheckBox")
90        self.assertTrue(l.is_displayed())
91        self.marionette.execute_script("arguments[0].hidden = true;", [l])
92        self.assertFalse(l.is_displayed())
93
94
95class TestGetElementAttribute(MarionetteTestCase):
96    def test_normal_attribute(self):
97        self.marionette.navigate(inline("<p style=foo>"))
98        el = self.marionette.find_element(By.TAG_NAME, "p")
99        attr = el.get_attribute("style")
100        self.assertIsInstance(attr, six.string_types)
101        self.assertEqual("foo", attr)
102
103    def test_boolean_attributes(self):
104        for tag, attrs in six.iteritems(boolean_attributes):
105            for attr in attrs:
106                print("testing boolean attribute <{0} {1}>".format(tag, attr))
107                doc = inline("<{0} {1}>".format(tag, attr))
108                self.marionette.navigate(doc)
109                el = self.marionette.find_element(By.TAG_NAME, tag)
110                res = el.get_attribute(attr)
111                self.assertIsInstance(res, six.string_types)
112                self.assertEqual("true", res)
113
114    def test_global_boolean_attributes(self):
115        self.marionette.navigate(inline("<p hidden>foo"))
116        el = self.marionette.find_element(By.TAG_NAME, "p")
117        attr = el.get_attribute("hidden")
118        self.assertIsInstance(attr, six.string_types)
119        self.assertEqual("true", attr)
120
121        self.marionette.navigate(inline("<p>foo"))
122        el = self.marionette.find_element(By.TAG_NAME, "p")
123        attr = el.get_attribute("hidden")
124        self.assertIsNone(attr)
125
126        self.marionette.navigate(inline("<p itemscope>foo"))
127        el = self.marionette.find_element(By.TAG_NAME, "p")
128        attr = el.get_attribute("itemscope")
129        self.assertIsInstance(attr, six.string_types)
130        self.assertEqual("true", attr)
131
132        self.marionette.navigate(inline("<p>foo"))
133        el = self.marionette.find_element(By.TAG_NAME, "p")
134        attr = el.get_attribute("itemscope")
135        self.assertIsNone(attr)
136
137    # TODO(ato): Test for custom elements
138
139    def test_xhtml(self):
140        doc = inline('<p hidden="true">foo</p>', doctype="xhtml")
141        self.marionette.navigate(doc)
142        el = self.marionette.find_element(By.TAG_NAME, "p")
143        attr = el.get_attribute("hidden")
144        self.assertIsInstance(attr, six.string_types)
145        self.assertEqual("true", attr)
146
147
148class TestGetElementProperty(MarionetteTestCase):
149    def test_get(self):
150        self.marionette.navigate(disabled)
151        el = self.marionette.find_element(By.TAG_NAME, "input")
152        prop = el.get_property("disabled")
153        self.assertIsInstance(prop, bool)
154        self.assertTrue(prop)
155
156    def test_missing_property_returns_default(self):
157        self.marionette.navigate(input)
158        el = self.marionette.find_element(By.TAG_NAME, "input")
159        prop = el.get_property("checked")
160        self.assertIsInstance(prop, bool)
161        self.assertFalse(prop)
162
163    def test_attribute_not_returned(self):
164        self.marionette.navigate(attribute)
165        el = self.marionette.find_element(By.TAG_NAME, "input")
166        self.assertEqual(el.get_property("foo"), None)
167
168    def test_manipulated_element(self):
169        self.marionette.navigate(check)
170        el = self.marionette.find_element(By.TAG_NAME, "input")
171        self.assertEqual(el.get_property("checked"), False)
172
173        el.click()
174        self.assertEqual(el.get_property("checked"), True)
175
176        el.click()
177        self.assertEqual(el.get_property("checked"), False)
178