[Pkg-mozext-commits] [requestpolicy] 71/257: [tst][add] RP Puppeteer "your_policy" library

David Prévot taffit at moszumanska.debian.org
Thu Jan 28 03:19:58 UTC 2016


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to branch master
in repository requestpolicy.

commit 0cc176b6375132707d8eeceaca095a688f99e94b
Author: Martin Kimmerle <dev at 256k.de>
Date:   Tue Oct 6 18:48:14 2015 +0200

    [tst][add] RP Puppeteer "your_policy" library
    
    This library allows to control the elements on the "Your Policy"
    settings page. Some parts of this library have been taken from
    the old `testRuleWithSchemeOnly.js` Mozmill test.
    
    The tests for the "Your Policy" library check that the "origin"
    and "destination" strings in the table are correct for all
    possible combinations of scheme, host and port. In case of a
    rule which only specifies a scheme, the test assumes the
    string `scheme "http"` if the scheme is "http". Previously
    the string was `http:*`, which however could be confused
    with `*://http:*`.
---
 src/content/settings/yourpolicy.js                 |  39 +-
 tests/marionette/rp_puppeteer/__init__.py          |   4 +
 tests/marionette/rp_puppeteer/base.py              |  60 +++
 tests/marionette/rp_puppeteer/errors.py            |   9 +
 tests/marionette/rp_puppeteer/tests/manifest.ini   |   1 +
 .../rp_puppeteer/tests/test_your_policy.py         | 475 +++++++++++++++++++++
 .../rp_puppeteer/ui/settings/__init__.py           |   1 +
 .../rp_puppeteer/ui/settings/your_policy.py        | 235 ++++++++++
 8 files changed, 815 insertions(+), 9 deletions(-)

diff --git a/src/content/settings/yourpolicy.js b/src/content/settings/yourpolicy.js
index 1b72ce1..9ca80d6 100644
--- a/src/content/settings/yourpolicy.js
+++ b/src/content/settings/yourpolicy.js
@@ -130,17 +130,38 @@ function addRulesTableRow(table, ruleAction, origin, dest, ruleData, source, rea
   }
 }
 
-// TODO: remove code duplication with menu.js
+/**
+ * Get a string representation of an endpoint (origin or dest) specification.
+ *
+ * The following list shows a mapping of the possible endpoint specs
+ * to the corresponding string representation. Each endpoint spec contains at
+ * least one of the parts "scheme", "host" and "port". The list shows the
+ * strings by example: scheme "http"; host "www.example.com"; port "80".
+ *
+ * - s__: `scheme "http"`
+ * - _h_: `www.example.com`
+ * - __p: `*://*:80`
+ * - sh_: `http://www.example.com`
+ * - s_p: `http://*:80`
+ * - _hp: `*://www.example.com:80`
+ * - shp: `http://www.example.com:80`
+ *
+ * TODO: remove code duplication with menu.js
+ */
 function ruleDataPartToDisplayString(ruleDataPart) {
+  if (ruleDataPart["s"] && !ruleDataPart["h"] && !ruleDataPart["port"]) {
+    // Special case: Only a scheme is specified.
+    //               The result string will be `scheme "..."`.
+    // Background info: The string could be `http:*`, but this could however
+    //                  be confused with `*://http:*`. The string `http://*`
+    //                  wouldn't be correct for all cases, since there are
+    //                  URIs _without_ a host.
+    return "scheme \"" + ruleDataPart["s"] + "\"";
+  }
   var str = "";
-  if (ruleDataPart["s"]) {
-    str += ruleDataPart["s"] + ":";
-
-    if (ruleDataPart["h"]) {
-      // In case no host has been specified, do not show the
-      // two slashes, as it might be an URI without a host.
-      str += "//";
-    }
+  if (ruleDataPart["s"] || ruleDataPart["port"]) {
+    str += ruleDataPart["s"] || "*";
+    str += "://";
   }
   str += ruleDataPart["h"] || "*";
   if (ruleDataPart["port"]) {
diff --git a/tests/marionette/rp_puppeteer/__init__.py b/tests/marionette/rp_puppeteer/__init__.py
index 43eed5c..7482250 100644
--- a/tests/marionette/rp_puppeteer/__init__.py
+++ b/tests/marionette/rp_puppeteer/__init__.py
@@ -43,3 +43,7 @@ class RequestPolicyPuppeteer(object):
     @use_class_as_property('ui.web_utils.WebUtils')
     def web_utils(self):
         pass
+
+    @use_class_as_property('ui.settings.your_policy.YourPolicy')
+    def your_policy(self):
+        pass
diff --git a/tests/marionette/rp_puppeteer/base.py b/tests/marionette/rp_puppeteer/base.py
new file mode 100644
index 0000000..028db7e
--- /dev/null
+++ b/tests/marionette/rp_puppeteer/base.py
@@ -0,0 +1,60 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from firefox_puppeteer.base import BaseLib
+from marionette_driver.marionette import HTMLElement
+
+
+class ElementBaseLib(BaseLib):
+    """A base class for all HTMLElement wrapper classes."""
+
+    def __init__(self, marionette_getter, element):
+        assert isinstance(element, HTMLElement)
+
+        BaseLib.__init__(self, marionette_getter)
+        self._element = element
+
+    @property
+    def element(self):
+        """Returns the reference to the underlying DOM element.
+
+        :returns: Reference to the DOM element.
+        """
+
+        return self._element
+
+
+class HTMLFormBaseLib(ElementBaseLib):
+    """A base class for all HTML form wrapper classes."""
+
+    @staticmethod
+    def input_field(find_method, find_target):
+        """Return a property attribute for an <input> form field.
+
+        The function takes care of finding the <input> HTML element and
+        getting/setting its `value` attribute. The parameters `find_method`
+        and `find_target` are passed to `Marionette.find_element()`.
+
+        :param find_method: The method to use to locate the <input> element.
+        :param find_target: The target of the search.
+        :returns: Property attribute.
+        """
+
+        return property(
+            lambda self: self._get_input_field_value(find_method, find_target),
+            lambda self, value: self._set_input_field_value(find_method,
+                                                            find_target, value))
+
+    def _get_input_field_value(self, find_method, find_target):
+        input_field = self._get_input_field(find_method, find_target)
+        return input_field.get_attribute("value")
+
+    def _set_input_field_value(self, find_method, find_target, value):
+        self.marionette.execute_script("""
+          arguments[0].value = arguments[1];
+        """, script_args=[self._get_input_field(find_method, find_target),
+                          value])
+
+    def _get_input_field(self, find_method, find_target):
+        return self.element.find_element(find_method, find_target)
diff --git a/tests/marionette/rp_puppeteer/errors.py b/tests/marionette/rp_puppeteer/errors.py
new file mode 100644
index 0000000..4b8231f
--- /dev/null
+++ b/tests/marionette/rp_puppeteer/errors.py
@@ -0,0 +1,9 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+# You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from marionette_driver.errors import MarionetteException
+
+
+class RadioButtonException(MarionetteException):
+    pass
diff --git a/tests/marionette/rp_puppeteer/tests/manifest.ini b/tests/marionette/rp_puppeteer/tests/manifest.ini
index ed8ad25..69b1fd1 100644
--- a/tests/marionette/rp_puppeteer/tests/manifest.ini
+++ b/tests/marionette/rp_puppeteer/tests/manifest.ini
@@ -4,3 +4,4 @@
 [test_prefs.py]
 [test_requests.py]
 [test_rules.py]
+[test_your_policy.py]
diff --git a/tests/marionette/rp_puppeteer/tests/test_your_policy.py b/tests/marionette/rp_puppeteer/tests/test_your_policy.py
new file mode 100644
index 0000000..5ca158c
--- /dev/null
+++ b/tests/marionette/rp_puppeteer/tests/test_your_policy.py
@@ -0,0 +1,475 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from rp_ui_harness import RequestPolicyTestCase
+from rp_puppeteer.api.rules import Rule
+from marionette import SkipTest
+from functools import partial
+
+
+class YourPolicyTestCase(RequestPolicyTestCase):
+
+    def setUp(self):
+        super(YourPolicyTestCase, self).setUp()
+
+        self.marionette.set_context("content")
+        self.your_policy.open()
+
+        self.rules_table = self.your_policy.rules_table
+        self.add_rule_form = self.your_policy.add_rule_form
+
+        #=======================================================================
+        # Create some rules for the tests
+        #=======================================================================
+
+        # Alias for `create_rule()`
+        cr = self.rules.create_rule
+
+        # some rules that should not collide with each other
+        self.allow_rule = cr({"o": {"h": "w"}}, allow=True, temp=False)
+        self.temp_allow_rule = cr({"o": {"h": "x"}}, allow=True, temp=True)
+        self.deny_rule = cr({"o": {"h": "y"}}, allow=False, temp=False)
+        self.temp_deny_rule = cr({"o": {"h": "z"}}, allow=False, temp=True)
+        self.some_rules = [self.allow_rule, self.temp_allow_rule,
+                           self.deny_rule, self.temp_deny_rule]
+
+        self.rule_without_origin = cr({"d": {"h": "foo"}}, allow=True)
+        self.rule_without_dest = cr({"o": {"h": "bar"}}, allow=True)
+
+        # A list of all possible pre-paths, including the expected string.
+        self.pre_path_specs = {
+            "s": {"spec": {"s": "s1"},
+                  # The string "s1:*" could be confused with "*://s1:*"
+                  "expected_string": 'scheme "s1"'},
+            "h": {"spec": {"h": "h2"},
+                  "expected_string": "h2"},
+            "p": {"spec": {"port": 3},
+                  "expected_string": "*://*:3"},
+            "sh": {"spec": {"s": "s4", "h": "h4"},
+                   "expected_string": "s4://h4"},
+            "sp": {"spec": {"s": "s5", "port": 5},
+                   "expected_string": "s5://*:5"},
+            "hp": {"spec": {"h": "h6", "port": 6},
+                   "expected_string": "*://h6:6"},
+            "shp": {"spec": {"s": "s7", "h": "h7", "port": 7},
+                    "expected_string": "s7://h7:7"}
+        }
+
+        self.allow_rule_shp_shp = cr({"o": {"s": "os", "h": "oh", "port": 1},
+                                      "d": {"s": "ds", "h": "dh", "port": 2}},
+                                     allow=True, temp=False)
+        self.temp_deny_rule_shp_shp = cr(
+                {"o": {"s": "os", "h": "oh", "port": 3},
+                 "d": {"s": "ds", "h": "dh", "port": 4}},
+                allow=False, temp=True)
+
+        self.allow_rule_sh_p = cr({"o": {"s": "os", "h": "oh"}, "d": {"port": 5}},
+                                  allow=True, temp=False)
+        self.temp_deny_rule_s_hp = cr({"o": {"s": "os"},
+                                       "d": {"h": "dh", "port": 4}},
+                                      allow=False, temp=True)
+        self.arbitrary_rule_shp_shp = cr(
+            {"o": {"s": "fooscheme", "h": "barhost", "port": 18224},
+             "d": {"s": "bazscheme", "h": "xyzhost", "port": 34755}},
+            allow=False, temp=True)
+
+    def tearDown(self):
+        try:
+            self.marionette.set_context("chrome")
+        finally:
+            super(YourPolicyTestCase, self).tearDown()
+
+    @property
+    def _user_rule_rows(self):
+        return self.rules_table.user_rule_rows
+
+
+class TestYourPolicy(YourPolicyTestCase):
+
+    def test_open(self):
+        self.marionette.navigate("about:blank")
+        self.assertNotEqual(self.marionette.get_url(),
+                            "about:requestpolicy?yourpolicy")
+        self.your_policy.open()
+        self.assertEqual(self.marionette.get_url(),
+                         "about:requestpolicy?yourpolicy")
+
+
+class TestRulesTable(YourPolicyTestCase):
+
+    def test_get_all_rule_rows(self):
+        raise SkipTest("The 'Rules' API doesn't support subscription rules "
+                       "yet.")
+
+    def test_get_user_rule_rows(self):
+        self.assertEqual(len(self._user_rule_rows), 0,
+                         "There are no user rules yet.")
+
+        # Add some rules
+        for rule in self.some_rules:
+            rule.add()
+
+        # Get the user rule rows.
+        user_rule_rows = self._user_rule_rows
+        # Compare the amount of rules.
+        self.assertEqual(len(user_rule_rows), len(self.some_rules),
+                         "The correct amount of rules have been added.")
+
+        # Convert rule-rows to `Rule` instances.
+        returned_rules = [row.create_rule() for row in user_rule_rows]
+
+        # Compare the two `Rule` lists.
+        self.assertEqual(returned_rules.sort(), self.some_rules.sort(),
+                         "All rules have been added and returned correctly.")
+
+    def test_get_rule_rows_by_ruleset_string(self):
+        permanent_rule = self.allow_rule
+        temporary_rule = self.temp_deny_rule
+
+        permanent_rule.add()
+        temporary_rule.add()
+
+        def get_rules(ruleset_string):
+            rule_rows = (
+                self.rules_table
+                .get_rule_rows_by_ruleset_string(ruleset_string)
+            )
+            return [row.create_rule() for row in rule_rows]
+
+        returned_temporary_rules = get_rules("Temporary")
+        returned_permanent_rules = get_rules("User")
+        rules_with_empty_ruleset_string = get_rules("")
+
+        self.assertEqual(returned_temporary_rules, [temporary_rule])
+        self.assertEqual(returned_permanent_rules, [permanent_rule])
+        self.assertEqual(rules_with_empty_ruleset_string, [])
+
+    def test_count_rules(self):
+        # Alias for `count_rules()`
+        count = self.rules_table.count_rules
+
+        self.assertEqual(self.rules.count_rules(), 0,
+                         "There are no user rules yet.")
+
+        # Remember the number of rule rows. The counter includes
+        # subscription rules.
+        num_rules_initial = count()
+
+        # Add a rule
+        self.some_rules[0].add()
+        self.assertEqual(count(), num_rules_initial + 1)
+
+        # Remove the rule
+        self.some_rules[0].remove()
+        self.assertEqual(count(), num_rules_initial)
+
+
+class TestRuleRow(YourPolicyTestCase):
+
+    def test_policy_property(self):
+        def assert_policy(policy_string_id):
+            # Get the localized policy string.
+            expected_policy_string = self.l10n.get_rp_property(policy_string_id)
+
+            rule_row = self._user_rule_rows[0]
+            returned_policy_string = rule_row.policy
+
+            self.assertEqual(returned_policy_string, expected_policy_string)
+
+        def test_rule(rule, policy_string_id):
+            rule.add()
+            assert_policy(policy_string_id)
+            rule.remove()
+
+        # Test using a rule with "allow" policy.
+        test_rule(self.allow_rule, "allow")
+
+        # Test using a rule with "deny" policy.
+        test_rule(self.deny_rule, "block")
+
+    def _test_endpoint(self, endpoint):
+        assert endpoint in ["origin", "dest"]
+
+        def test(spec_id):
+            self._test_pre_path_spec(endpoint, self.pre_path_specs[spec_id])
+
+        test("s")
+        test("h")
+        test("p")
+        test("sh")
+        test("sp")
+        test("hp")
+        test("shp")
+
+    def _test_pre_path_spec(self, endpoint, spec):
+        def create_rule():
+            """Create the rule from the spec info."""
+            endpoint_short = "o" if endpoint == "origin" else "d"
+            rule_data = {endpoint_short: spec["spec"]}
+            return self.rules.create_rule(rule_data, allow=True)
+
+        # Create and add the rule.
+        rule = create_rule()
+        rule.add()
+
+        # Check if the cell text matches the expected string.
+        rule_row = self._user_rule_rows[0]
+        returned_string = getattr(rule_row, endpoint)
+        self.assertEqual(returned_string, spec["expected_string"])
+
+        # Remove the rule again.
+        rule.remove()
+
+    def test_origin_property(self):
+        self._test_endpoint("origin")
+
+    def test_dest_property(self):
+        self._test_endpoint("dest")
+
+    def test_origin_empty(self):
+        self.rule_without_origin.add()
+        origin_string = self._user_rule_rows[0].origin
+        self.assertEqual(origin_string, "")
+
+    def test_dest_empty(self):
+        self.rule_without_dest.add()
+        dest_string = self._user_rule_rows[0].dest
+        self.assertEqual(dest_string, "")
+
+    def test_rule_set_property(self):
+        def test(rule, expected_ruleset_string):
+            rule.add()
+            self.assertEqual(self._user_rule_rows[0].rule_set,
+                             expected_ruleset_string)
+            rule.remove()
+
+        test(self.allow_rule, "User")
+        test(self.temp_allow_rule, "Temporary")
+
+    def test_create_rule(self):
+        def test(rule):
+            rule.add()
+            rule_row = self._user_rule_rows[0]
+            returned_rule = rule_row.create_rule()
+            self.assertIsInstance(returned_rule, Rule,
+                                  "`create_rule()` has returned a `Rule` "
+                                  "instance.")
+            self.assertEqual(returned_rule, rule,
+                             msg=("The returned rule is identical to what "
+                                  "has been added."))
+            rule.remove()
+
+        # Test rules with all origin/dest fields specified.
+        test(self.allow_rule_shp_shp)
+        test(self.temp_deny_rule_shp_shp)
+
+    def test_remove_rule(self):
+        for rule in self.some_rules:
+            rule.add()
+            self.assertTrue(rule.exists())
+            self._user_rule_rows[0].remove()
+            self.assertFalse(rule.exists())
+
+    def test_is_user_rule(self):
+        def test_rule(rule, is_user_rule):
+            rule.add()
+            self.assertEqual(self._user_rule_rows[0].is_user_rule(),
+                             is_user_rule)
+            rule.remove()
+
+        # Test some user rules, that is, both temporary and permanent rules.
+        test_rule(self.allow_rule, True)
+        test_rule(self.temp_allow_rule, True)
+
+        # TODO: Test some non-user rules (subscription rules).
+        #       In those cases `is_user_rule()` should return `False`.
+
+    def test_is_temporary(self):
+        def test_rule(rule, is_temp):
+            rule.add()
+            self.assertEqual(self._user_rule_rows[0].is_temporary(), is_temp)
+            rule.remove()
+
+        # Test both temporary and permanent rules.
+        test_rule(self.allow_rule, False)
+        test_rule(self.temp_allow_rule, True)
+
+
+class TestAddRuleForm(YourPolicyTestCase):
+
+    def setUp(self):
+        super(TestAddRuleForm, self).setUp()
+
+        self.input_field_values = {"allow": True, "temp": True,
+                                   "origin_scheme": "os", "origin_host": "oh",
+                                   "origin_port": "op", "dest_scheme": "ds",
+                                   "dest_host": "dh", "dest_port": "dp"}
+
+    def test_input_fields(self):
+        def test_input_field(field_name, set_value, reset_value):
+            """ Procedure:
+                1. Set the input field to a value.
+                2. Assertion
+                3. Reset the input field.
+                4. Assertion
+            """
+            form = self.add_rule_form
+            setattr(form, field_name, set_value)
+            self.assertEqual(getattr(form, field_name), set_value)
+            setattr(form, field_name, reset_value)
+            self.assertEqual(getattr(form, field_name), reset_value)
+
+        test_boolean_field = partial(test_input_field, set_value=True,
+                                     reset_value=False)
+        test_text_field = partial(test_input_field, set_value="foo",
+                                  reset_value="")
+
+        test_boolean_field("allow")
+        test_boolean_field("temp")
+        test_text_field("origin_scheme")
+        test_text_field("origin_host")
+        test_text_field("origin_port")
+        test_text_field("dest_scheme")
+        test_text_field("dest_host")
+        test_text_field("dest_port")
+
+    def test_set_all_values__specifying_only_one_field(self):
+        def test_one_field(field_name, value):
+            # Fill all fields with some data, to see that fields not
+            # specified to `set_all_values` are reset.
+            self._fill_all_fields()
+
+            # Set all fields
+            self.add_rule_form.set_all_values(**{field_name: value})
+
+            # Check all fields
+            self._assert_all_fields_are_reset(ignore_fields=[field_name])
+            self.assertEqual(getattr(self.add_rule_form, field_name), value,
+                             ("Form field `{}` has value `{}`."
+                              .format(field_name, value)))
+
+        for field_name, value in self.input_field_values.items():
+            test_one_field(field_name, value)
+
+    def test_set_all_values__specifying_all_fields(self):
+        self._fill_all_fields()
+
+        # Set all fields
+        self.add_rule_form.set_all_values(**self.input_field_values)
+
+        # Check all fields
+        for field_name, value in self.input_field_values.items():
+            self.assertEqual(getattr(self.add_rule_form, field_name), value,
+                             ("Form field `{}` has value `{}`."
+                              .format(field_name, value)))
+
+    def test_set_all_values_by_rule(self):
+
+        def get_expected_field_values_from_rule(rule):
+            return {"allow": rule.allow, "temp": rule.temp,
+                    "origin_scheme": rule.origin_scheme or "",
+                    "origin_host": rule.origin_host or "",
+                    "origin_port": str(rule.origin_port or ""),
+                    "dest_scheme": rule.dest_scheme or "",
+                    "dest_host": rule.dest_host or "",
+                    "dest_port": str(rule.dest_port or "")}
+
+        def test_rule(rule):
+            # Set all values
+            self.add_rule_form.set_all_values_by_rule(rule)
+
+            # Assertions
+            expected_values = get_expected_field_values_from_rule(rule)
+            for field_name, expected_field_value in expected_values.items():
+                # Compare the expected value with the value returned by
+                # the `AddRuleForm` property getters.
+                returned_field_value = getattr(self.add_rule_form, field_name)
+                self.assertEqual(returned_field_value, expected_field_value,
+                                 msg=("Form field `{}` has value `{}`."
+                                      .format(field_name,
+                                              expected_field_value)))
+
+        # Test some rules which make use of all fields.
+        test_rule(self.allow_rule_shp_shp)
+        test_rule(self.temp_deny_rule_shp_shp)
+
+        # Test some rules which make use of _some_ fields.
+        test_rule(self.allow_rule_sh_p)
+        test_rule(self.temp_deny_rule_s_hp)
+        test_rule(self.rule_without_dest)
+        test_rule(self.rule_without_origin)
+
+    def test_reset(self):
+        # Set all fields.
+        self.add_rule_form.set_all_values_by_rule(self.temp_deny_rule_shp_shp)
+
+        # reset
+        self.add_rule_form.reset()
+
+        self._assert_all_fields_are_reset()
+
+    def test_submit(self):
+        def submit_and_compare(expected_rule):
+            self.assertEqual(len(self._user_rule_rows), 0)
+            self.add_rule_form.submit()
+            # If `expected_rule` is None, no rule should be created.
+            expected_count = 1 if expected_rule is not None else 0
+            self.assertEqual(len(self._user_rule_rows), expected_count)
+            if expected_count != 0:
+                submitted_rule = self._user_rule_rows[0].create_rule()
+                self.assertEqual(submitted_rule, expected_rule)
+
+        def test_rule(rule):
+            """ Procedure:
+                (1) Fill the form using the `Rule` instance`.
+                (2) Submit the form.
+                (3) Get the `RuleRow` and compare its values with those
+                    of the `Rule` instance.
+            """
+            # Fill the form.
+            self.add_rule_form.set_all_values_by_rule(rule)
+            # Submit and compare.
+            submit_and_compare(rule)
+            # Remove the rule again.
+            rule.remove()
+
+        # Test some rules which make use of all fields.
+        test_rule(self.allow_rule_shp_shp)
+        test_rule(self.temp_deny_rule_shp_shp)
+
+        # Test some rules which make use of _some_ fields.
+        test_rule(self.allow_rule_sh_p)
+        test_rule(self.temp_deny_rule_s_hp)
+        test_rule(self.rule_without_dest)
+        test_rule(self.rule_without_origin)
+
+        # If all form fields are empty, no rule should be added.
+        self.add_rule_form.reset()
+        submit_and_compare(None)
+
+    def _assert_all_fields_are_reset(self, ignore_fields=[]):
+        """Assert that the form is empty/reset."""
+
+        def check_field(field_name, expected_value=""):
+            if field_name in ignore_fields:
+                return
+            self.assertEqual(getattr(self.add_rule_form, field_name),
+                             expected_value,
+                             "Field `{}` is empty.".format(field_name))
+
+        check_field("origin_scheme")
+        check_field("origin_host")
+        check_field("origin_port")
+        check_field("dest_scheme")
+        check_field("dest_host")
+        check_field("dest_port")
+
+        # The `temp` checkbox should be unchecked.
+        check_field("temp", expected_value=False)
+
+    def _fill_all_fields(self):
+        """Fill all form fields with some data."""
+
+        rule = self.arbitrary_rule_shp_shp
+        self.add_rule_form.set_all_values_by_rule(rule)
diff --git a/tests/marionette/rp_puppeteer/ui/settings/__init__.py b/tests/marionette/rp_puppeteer/ui/settings/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/tests/marionette/rp_puppeteer/ui/settings/__init__.py
@@ -0,0 +1 @@
+
diff --git a/tests/marionette/rp_puppeteer/ui/settings/your_policy.py b/tests/marionette/rp_puppeteer/ui/settings/your_policy.py
new file mode 100644
index 0000000..33d02cd
--- /dev/null
+++ b/tests/marionette/rp_puppeteer/ui/settings/your_policy.py
@@ -0,0 +1,235 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+from rp_puppeteer.base import BaseLib, ElementBaseLib, HTMLFormBaseLib
+from rp_puppeteer.errors import RadioButtonException
+from rp_puppeteer.api.rules import Rule
+
+
+class YourPolicy(BaseLib):
+
+    @property
+    def add_rule_form(self):
+        form = self.marionette.find_element("id", "addruleform")
+        return AddRuleForm(lambda: self.marionette, form)
+
+    @property
+    def rules_table(self):
+        return RulesTable(lambda: self.marionette)
+
+    def open(self):
+        self.marionette.navigate("about:requestpolicy?yourpolicy")
+
+
+class RulesTable(BaseLib):
+
+    #################################
+    # Public Properties and Methods #
+    #################################
+
+    @property
+    def all_rule_rows(self):
+        """Get a list of all rules."""
+
+        tr_elements = self._tbody.find_elements("tag name", "tr")
+        return self._create_rule_rows(tr_elements)
+
+    @property
+    def user_rule_rows(self):
+        """Get a list of all user rules."""
+
+        rows = []
+        for ruleset_string in ["Temporary", "User"]:
+            rows += self.get_rule_rows_by_ruleset_string(ruleset_string)
+        return rows
+
+    def get_rule_rows_by_ruleset_string(self, ruleset_string):
+        # XPath to get all <tr> elements where the fourth <td> child (the
+        # rule-set column) contains the exact string `ruleset_string`.
+        xpath = "tr[./td[4]='{}']".format(ruleset_string)
+        tr_elements = self._tbody.find_elements("xpath", xpath)
+        return self._create_rule_rows(tr_elements)
+
+    def count_rules(self):
+        return self.marionette.execute_script("""
+          return arguments[0].children.length
+        """, script_args=[self._tbody])
+
+    ##################################
+    # Private Properties and Methods #
+    ##################################
+
+    @property
+    def _tbody(self):
+        return self.marionette.find_element("id", "rules")
+
+    @property
+    def _filter_field(self):
+        return self.marionette.find_element("id", "rulesearch")
+
+    def _create_rule_rows(self, tr_elements):
+        return [RuleRow(lambda: self.marionette, tr) for tr in tr_elements]
+
+
+class RuleRow(ElementBaseLib):
+
+    #################################
+    # Public Properties and Methods #
+    #################################
+
+    # Properties to get the strings of the corresponding table cells.
+    policy = property(lambda self: self._get_cell_text_content(0))
+    origin = property(lambda self: self._get_cell_text_content(1))
+    dest = property(lambda self: self._get_cell_text_content(2))
+    rule_set = property(lambda self: self._get_cell_text_content(3))
+
+    def create_rule(self):
+        """Create a `Rule` instance for this rule row."""
+
+        if not self.is_user_rule():
+            # Getting non-user (e.g. subscription) rules is not implemented yet.
+            raise NotImplementedError
+
+        # The rule details are retained by RequestPolicy via `jQuery.data()`
+        # on the "<a>x</a>" HTML anchor element, the element being clicked to
+        # remove the rule.
+        [rule_action, rule_data] = self.marionette.execute_script("""
+          var anchor = $(arguments[0]);
+          return [
+            anchor.data('requestpolicyRuleAction'),
+            anchor.data('requestpolicyRuleData')
+          ];
+        """, script_args=[self._remove_anchor])
+
+        allow = True if rule_action == "allow" else False
+        temp = self.is_temporary()
+
+        return Rule(lambda: self.marionette, rule_data, allow, temp)
+
+    def remove(self):
+        self._remove_anchor.click()
+
+    def is_user_rule(self):
+        return self.rule_set in ["User", "Temporary"]
+
+    def is_temporary(self):
+        return self.rule_set == "Temporary"
+
+    ##################################
+    # Private Properties and Methods #
+    ##################################
+
+    @property
+    def _cells(self):
+        return self.element.find_elements("tag name", "td")
+
+    def _get_cell_text_content(self, column_index):
+        return self._cells[column_index].get_attribute("textContent")
+
+    @property
+    def _remove_anchor(self):
+        return self._cells[4].find_element("tag name", "a")
+
+
+class AddRuleForm(HTMLFormBaseLib):
+
+    #################################
+    # Public Properties and Methods #
+    #################################
+
+    @property
+    def allow(self):
+        allow_selected = self._allow_radio_button.is_selected()
+        deny_selected = self._deny_radio_button.is_selected()
+        if allow_selected == deny_selected:
+            # Either both or none of the radio buttons is selected.
+            raise RadioButtonException
+        return allow_selected
+
+    @allow.setter
+    def allow(self, value):
+        if value:
+            self._allow_radio_button.click()
+        else:
+            self._deny_radio_button.click()
+
+    @property
+    def temp(self):
+        return self._temp_check_box.is_selected()
+
+    @temp.setter
+    def temp(self, value):
+        if self.temp != value:
+            # Toggle the value.
+            self._temp_check_box.click()
+
+    # Property attributes to get the <input> HTML elements.
+    origin_scheme = HTMLFormBaseLib.input_field("name", "originscheme")
+    origin_host = HTMLFormBaseLib.input_field("name", "originhost")
+    origin_port = HTMLFormBaseLib.input_field("name", "originport")
+    dest_scheme = HTMLFormBaseLib.input_field("name", "destscheme")
+    dest_host = HTMLFormBaseLib.input_field("name", "desthost")
+    dest_port = HTMLFormBaseLib.input_field("name", "destport")
+
+    def set_all_values(self, allow=True, origin_scheme="", origin_host="",
+                       origin_port="", dest_scheme="", dest_host="",
+                       dest_port="", temp=False):
+        """Fill all form fields.
+
+        All parameters are optional, but all fields will be set. All fields
+        whose parameters arent's specified will be reset.
+        """
+
+        self.allow = allow
+        self.temp = temp
+        self.origin_scheme = origin_scheme
+        self.origin_host = origin_host
+        self.origin_port = origin_port
+        self.dest_scheme = dest_scheme
+        self.dest_host = dest_host
+        self.dest_port = dest_port
+
+    def set_all_values_by_rule(self, rule):
+        """Fill the form using a `Rule` instance."""
+
+        self.allow = rule.allow
+        self.temp = rule.temp
+
+        for field_name in ["origin_scheme", "origin_host", "origin_port",
+                           "dest_scheme", "dest_host", "dest_port"]:
+            # Get the field's value. If the value is not set it will be `None`,
+            # so in that case `value` will be an empty string.
+            value = getattr(rule, field_name) or ""
+            setattr(self, field_name, value)
+
+    def reset(self):
+        """Reset all fields to its default value."""
+
+        self.set_all_values()
+
+    def submit(self):
+        """Submit the form."""
+
+        self._submit_button.click()
+
+    ##################################
+    # Private Properties and Methods #
+    ##################################
+
+    @property
+    def _allow_radio_button(self):
+        return self.element.find_element("id", "allowrule")
+
+    @property
+    def _deny_radio_button(self):
+        return self.element.find_element("id", "denyrule")
+
+    @property
+    def _temp_check_box(self):
+        return self.element.find_element("id", "temporary")
+
+    @property
+    def _submit_button(self):
+        return self.element.find_element("css selector",
+                                         "button[data-string=addRule]")

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/requestpolicy.git



More information about the Pkg-mozext-commits mailing list