Repository: ManageIQ/integration_tests

Issue:
[Bug] Condition creation fails with StaleElementReferenceException
Unable to create a condition via `appliance.collections.conditions.create()` method

cf. `cfme/control/explorer/conditions.py`

e.g. [here](https://github.com/ManageIQ/integration_tests/blob/0751cabee21c8ff1b25cc1b87aee21fa981b5ca7/cfme/control/explorer/conditions.py#L237)
``` 
condition = condition_collection.create(
    condition_class,
    fauxfactory.gen_alphanumeric(),
    expression="fill_field({} : Address )".format(
        condition_class.FIELD_VALUE),
    scope="fill_field({} : Name, INCLUDES, {})".format(
        condition_class.FIELD_VALUE, fauxfactory.gen_alpha())
)
```

This will raise `StaleElementReferenceException: Message: Couldn't handle it` and appears to impact CFME 5.9 as well as 5.10. Once at this page, it is not possible to navigate via the Accordion, as it is grayed out. Seems to be impacting several test cases, but is most relevant for tests in:
`cfme/tests/control/test_basic.py` [here](https://github.com/ManageIQ/integration_tests/blob/0751cabee21c8ff1b25cc1b87aee21fa981b5ca7/cfme/tests/control/test_basic.py#L530)



Discussion:

Resolving patch:
diff --git a/cfme/control/explorer/conditions.py b/cfme/control/explorer/conditions.py
--- a/cfme/control/explorer/conditions.py
+++ b/cfme/control/explorer/conditions.py
@@ -1,6 +1,5 @@
 # -*- coding: utf-8 -*-
 import attr
-from wait_for import wait_for
 
 from navmazing import NavigateToAttribute, NavigateToSibling
 from widgetastic.widget import Text, TextInput, Widget
@@ -77,8 +76,8 @@ class ConditionFormCommon(ControlExplorerView):
 
     title = Text("#explorer_title_text")
     description = Input(name="description")
-    scope = ExpressionEditor("//img[@alt='Edit this Scope']")
-    expression = ExpressionEditor("//img[@alt='Edit this Expression']")
+    scope = ExpressionEditor("//button[normalize-space(.)='Define Scope']")
+    expression = ExpressionEditor("//button[normalize-space(.)='Define Expression']")
     notes = TextInput(name="notes")
 
     cancel_button = Button("Cancel")
@@ -101,6 +100,21 @@ def is_displayed(self):
         )
 
 
+class ConditionClassAllView(ControlExplorerView):
+    title = Text("#explorer_title_text")
+
+    @property
+    def is_displayed(self):
+        return (
+            self.in_control_explorer and
+            self.title.text == "All {} Conditions".format(self.context["object"].FIELD_VALUE) and
+            self.conditions.is_opened and
+            self.conditions.tree.currently_selected == [
+                "All Conditions","{} Conditions".format(self.context["object"].TREE_NODE)
+            ]
+        )
+
+
 class EditConditionView(ConditionFormCommon):
     title = Text("#explorer_title_text")
 
@@ -111,8 +125,10 @@ class EditConditionView(ConditionFormCommon):
     def is_displayed(self):
         return (
             self.in_control_explorer and
-            self.title.text == '{} "{}"'.format(self.context["object"].FIELD_VALUE,
-                self.context["object"].description) and
+            self.title.text == 'Editing {} Condition "{}"'.format(
+                self.context["object"].FIELD_VALUE,
+                self.context["object"].description
+            ) and
             self.conditions.is_opened and
             self.conditions.tree.currently_selected == [
                 "All Conditions",
@@ -183,8 +199,7 @@ def update(self, updates):
         view.fill(updates)
         view.save_button.click()
         view = self.create_view(ConditionDetailsView, override=updates)
-        wait_for(lambda: view.is_displayed, timeout=10,
-            message="wait until ConditionDetailsView will be displayed")
+        view.wait_displayed()
         view.flash.assert_success_message(
             'Condition "{}" was saved'.format(updates.get("description", self.description)))
 
@@ -201,8 +216,8 @@ def delete(self, cancel=False):
             assert view.is_displayed
             view.flash.assert_no_error()
         else:
-            view = self.create_view(ConditionsAllView)
-            assert view.is_displayed
+            view = self.create_view(ConditionClassAllView)
+            view.wait_displayed()
             view.flash.assert_success_message('Condition "{}": Delete successful'.format(
                 self.description))
 
@@ -238,12 +253,14 @@ def create(self, condition_class, description, expression=None, scope=None, note
         condition = condition_class(self, description, expression=expression, scope=scope,
             notes=notes)
         view = navigate_to(condition, "Add")
+        # first fill description, expression, and notes
         view.fill({
             "description": condition.description,
             "expression": condition.expression,
             "scope": condition.scope,
             "notes": condition.notes
         })
+        view.wait_displayed()
         view.add_button.click()
         view = condition.create_view(ConditionDetailsView)
         assert view.is_displayed
diff --git a/widgetastic_manageiq/expression_editor.py b/widgetastic_manageiq/expression_editor.py
--- a/widgetastic_manageiq/expression_editor.py
+++ b/widgetastic_manageiq/expression_editor.py
@@ -3,6 +3,7 @@
 
 """
 import re
+import time
 from functools import partial
 
 import six
@@ -12,6 +13,7 @@
 from widgetastic_patternfly import BootstrapSelect as VanillaBootstrapSelect
 from widgetastic_patternfly import Button, Input
 
+from cfme.utils.blockers import BZ
 from cfme.utils.pretty import Pretty
 from cfme.utils.wait import TimedOutError, wait_for
 from widgetastic_manageiq import Calendar, Checkbox
@@ -31,6 +33,11 @@ def fill(self, value):
         # should wait until it appears and only then we can fill it.
         self.logger.info("FILLING WIDGET %s", str(self))
         self.wait_displayed()
+        # BZ 1649057 documents that a loading screen appears twice when a scope or expression
+        # element is selected. Between loads, the page is displayed and we make a selection, which
+        # is then overwritten in the next load. This work-around will wait for both loads.
+        if BZ(1649057, forced_streams=["5.9", "5.10"]).blocks:
+            time.sleep(1)
         super(BootstrapSelect, self).fill(value)
 
 


Test patch: