From 21e7bc5128b42c54b204cf7558aff65889850d11 Mon Sep 17 00:00:00 2001
From: Jay Zoldak <jzoldak@edx.org>
Date: Thu, 7 Mar 2013 11:01:15 -0500
Subject: [PATCH] More robust handling for finding and clicking on objects by
 css. Tag tests not working under PhantomJS to skip for now.

---
 .gitignore                                    |  3 +-
 .../features/advanced-settings.feature        |  3 +
 .../features/advanced-settings.py             | 57 +++++++++++--------
 .../contentstore/features/common.py           | 41 ++++---------
 .../contentstore/features/section.feature     |  1 +
 .../studio-overview-togglesection.feature     |  1 +
 .../contentstore/features/subsection.feature  |  1 +
 common/djangoapps/terrain/browser.py          |  3 +-
 8 files changed, 55 insertions(+), 55 deletions(-)

diff --git a/.gitignore b/.gitignore
index 493df5a7fdd..b13a128a637 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,4 +28,5 @@ nosetests.xml
 cover_html/
 .idea/
 .redcar/
-chromedriver.log
\ No newline at end of file
+chromedriver.log
+ghostdriver.log
diff --git a/cms/djangoapps/contentstore/features/advanced-settings.feature b/cms/djangoapps/contentstore/features/advanced-settings.feature
index 4708a60be1b..779d44e4b2c 100644
--- a/cms/djangoapps/contentstore/features/advanced-settings.feature
+++ b/cms/djangoapps/contentstore/features/advanced-settings.feature
@@ -7,6 +7,7 @@ Feature: Advanced (manual) course policy
     When I select the Advanced Settings
     Then I see only the display name
 
+  @skip-phantom
   Scenario: Test if there are no policy settings without existing UI controls
     Given I am on the Advanced Course Settings page in Studio
     When I delete the display name
@@ -14,6 +15,7 @@ Feature: Advanced (manual) course policy
     And I reload the page
     Then there are no advanced policy settings
 
+  @skip-phantom
   Scenario: Test cancel editing key name
     Given I am on the Advanced Course Settings page in Studio
     When I edit the name of a policy key
@@ -32,6 +34,7 @@ Feature: Advanced (manual) course policy
     And I press the "Cancel" notification button
     Then the policy key value is unchanged
 
+  @skip-phantom
   Scenario: Test editing key value
     Given I am on the Advanced Course Settings page in Studio
     When I edit the value of a policy key
diff --git a/cms/djangoapps/contentstore/features/advanced-settings.py b/cms/djangoapps/contentstore/features/advanced-settings.py
index 4ce9421ad3b..dbbe769b8e1 100644
--- a/cms/djangoapps/contentstore/features/advanced-settings.py
+++ b/cms/djangoapps/contentstore/features/advanced-settings.py
@@ -2,9 +2,9 @@ from lettuce import world, step
 from common import *
 import time
 from selenium.common.exceptions import WebDriverException
+from selenium.webdriver.support import expected_conditions as EC
 
-from nose.tools import assert_equal
-from nose.tools import assert_true
+from nose.tools import assert_true, assert_false, assert_equal
 
 """
 http://selenium.googlecode.com/svn/trunk/docs/api/py/webdriver/selenium.webdriver.common.keys.html
@@ -20,6 +20,7 @@ def i_select_advanced_settings(step):
         css_click(expand_icon_css)
     link_css = 'li.nav-course-settings-advanced a'
     css_click(link_css)
+    # world.browser.click_link_by_text('Advanced Settings')
 
 
 @step('I am on the Advanced Course Settings page in Studio$')
@@ -43,12 +44,20 @@ def edit_the_name_of_a_policy_key(step):
 
 @step(u'I press the "([^"]*)" notification button$')
 def press_the_notification_button(step, name):
+    def is_visible(driver):
+        return EC.visibility_of_element_located((By.CSS_SELECTOR,css,))
+    def is_invisible(driver):
+        return EC.invisibility_of_element_located((By.CSS_SELECTOR,css,))
+
+    css = 'a.%s-button' % name.lower()
+    wait_for(is_visible)
+
     try:
-        world.browser.click_link_by_text(name)
+        css_click_at(css)
+        wait_for(is_invisible)
     except WebDriverException, e:
-        css = 'a.%s-button' % name.lower()
         css_click_at(css)
-
+        wait_for(is_invisible)
 
 @step(u'I edit the value of a policy key$')
 def edit_the_value_of_a_policy_key(step):
@@ -104,29 +113,29 @@ def it_is_formatted(step):
 @step(u'the policy key name is unchanged$')
 def the_policy_key_name_is_unchanged(step):
     policy_key_css = 'input.policy-key'
-    e = css_find(policy_key_css).first
-    assert_equal(e.value, 'display_name')
+    val = css_find(policy_key_css).first.value
+    assert_equal(val, 'display_name')
 
 
 @step(u'the policy key name is changed$')
 def the_policy_key_name_is_changed(step):
     policy_key_css = 'input.policy-key'
-    e = css_find(policy_key_css).first
-    assert_equal(e.value, 'new')
+    val = css_find(policy_key_css).first.value
+    assert_equal(val, 'new')
 
 
 @step(u'the policy key value is unchanged$')
 def the_policy_key_value_is_unchanged(step):
     policy_value_css = 'li.course-advanced-policy-list-item div.value textarea'
-    e = css_find(policy_value_css).first
-    assert_equal(e.value, '"Robot Super Course"')
+    val = css_find(policy_value_css).first.value
+    assert_equal(val, '"Robot Super Course"')
 
 
 @step(u'the policy key value is changed$')
 def the_policy_key_value_is_unchanged(step):
     policy_value_css = 'li.course-advanced-policy-list-item div.value textarea'
-    e = css_find(policy_value_css).first
-    assert_equal(e.value, '"Robot Super Course X"')
+    val = css_find(policy_value_css).first.value
+    assert_equal(val, '"Robot Super Course X"')
 
 
 ############# HELPERS ###############
@@ -149,7 +158,7 @@ def delete_entry(index):
     """ 
     Delete the nth entry where index is 0-based
     """
-    css = '.delete-button'
+    css = 'a.delete-button'
     assert_true(world.browser.is_element_present_by_css(css, 5))
     delete_buttons = css_find(css)
     assert_true(len(delete_buttons) > index, "no delete button exists for entry " + str(index))
@@ -170,16 +179,16 @@ def assert_entries(css, expected_values):
 
 
 def click_save():
-    css = ".save-button"
-
-    def is_shown(driver):
-        visible = css_find(css).first.visible
-        if visible:
-            # Even when waiting for visible, this fails sporadically. Adding in a small wait.
-            time.sleep(float(1))
-        return visible
-    wait_for(is_shown)
-    css_click(css)
+    css = "a.save-button"
+
+    # def is_shown(driver):
+    #     visible = css_find(css).first.visible
+    #     if visible:
+    #         # Even when waiting for visible, this fails sporadically. Adding in a small wait.
+    #         time.sleep(float(1))
+    #     return visible
+    # wait_for(is_shown)
+    css_click_at(css)
 
 
 def fill_last_field(value):
diff --git a/cms/djangoapps/contentstore/features/common.py b/cms/djangoapps/contentstore/features/common.py
index b6e2b2b4292..f7e76ecf7f8 100644
--- a/cms/djangoapps/contentstore/features/common.py
+++ b/cms/djangoapps/contentstore/features/common.py
@@ -3,7 +3,9 @@ from lettuce.django import django_url
 from nose.tools import assert_true
 from nose.tools import assert_equal
 from selenium.webdriver.support.ui import WebDriverWait
-from selenium.common.exceptions import WebDriverException
+from selenium.common.exceptions import WebDriverException, StaleElementReferenceException
+from selenium.webdriver.support import expected_conditions as EC
+from selenium.webdriver.common.by import By
 
 from terrain.factories import UserFactory, RegistrationFactory, UserProfileFactory
 from terrain.factories import CourseFactory, GroupFactory
@@ -15,8 +17,6 @@ from logging import getLogger
 logger = getLogger(__name__)
 
 ###########  STEP HELPERS ##############
-
-
 @step('I (?:visit|access|open) the Studio homepage$')
 def i_visit_the_studio_homepage(step):
     # To make this go to port 8001, put
@@ -54,9 +54,8 @@ def i_have_opened_a_new_course(step):
     log_into_studio()
     create_a_course()
 
-####### HELPER FUNCTIONS ##############
-
 
+####### HELPER FUNCTIONS ##############
 def create_studio_user(
         uname='robot',
         email='robot+studio@edx.org',
@@ -97,35 +96,15 @@ def assert_css_with_text(css, text):
 
 def css_click(css):
     '''
-<<<<<<< HEAD
-<<<<<<< HEAD
-=======
->>>>>>> Catch WebDriverException
     First try to use the regular click method, 
     but if clicking in the middle of an element
     doesn't work it might be that it thinks some other
     element is on top of it there so click in the upper left
-<<<<<<< HEAD
     '''
     try:
-        assert_true(world.browser.is_element_present_by_css(css, 5))
-        world.browser.find_by_css(css).first.click()
+        css_find(css).first.click()
     except WebDriverException, e:
         css_click_at(css)
-=======
-    Rather than click in the middle of an element, 
-    click in the upper left
-    '''
-    css_click_at(css)
->>>>>>> Click in the upper left of an element instead of the middle.
-=======
-    '''
-    try:
-        assert_true(world.browser.is_element_present_by_css(css, 5))
-        world.browser.find_by_css(css).first.click()
-    except WebDriverException, e:
-        css_click_at(css)
->>>>>>> Catch WebDriverException
 
 
 def css_click_at(css, x=10, y=10):
@@ -133,8 +112,7 @@ def css_click_at(css, x=10, y=10):
     A method to click at x,y coordinates of the element
     rather than in the center of the element
     '''
-    assert_true(world.browser.is_element_present_by_css(css, 5))
-    e = world.browser.find_by_css(css).first
+    e = css_find(css).first
     e.action_chains.move_to_element_with_offset(e._element, x, y)
     e.action_chains.click()
     e.action_chains.perform()
@@ -145,11 +123,16 @@ def css_fill(css, value):
 
 
 def css_find(css):
+    def is_visible(driver):
+        return EC.visibility_of_element_located((By.CSS_SELECTOR,css,))
+
+    assert_true(world.browser.is_element_present_by_css(css, 5))
+    wait_for(is_visible)
     return world.browser.find_by_css(css)
 
 
 def wait_for(func):
-    WebDriverWait(world.browser.driver, 10).until(func)
+    WebDriverWait(world.browser.driver, 5).until(func)
 
 
 def id_find(id):
diff --git a/cms/djangoapps/contentstore/features/section.feature b/cms/djangoapps/contentstore/features/section.feature
index 75e7a4af10c..93ff1ca2476 100644
--- a/cms/djangoapps/contentstore/features/section.feature
+++ b/cms/djangoapps/contentstore/features/section.feature
@@ -26,6 +26,7 @@ Feature: Create Section
     And I save a new section release date
     Then the section release date is updated
 
+  @skip-phantom
   Scenario: Delete section
     Given I have opened a new course in Studio
     And I have added a new section
diff --git a/cms/djangoapps/contentstore/features/studio-overview-togglesection.feature b/cms/djangoapps/contentstore/features/studio-overview-togglesection.feature
index 5276b90d124..52c10e41a86 100644
--- a/cms/djangoapps/contentstore/features/studio-overview-togglesection.feature
+++ b/cms/djangoapps/contentstore/features/studio-overview-togglesection.feature
@@ -21,6 +21,7 @@ Feature: Overview Toggle Section
 		Then I see the "Collapse All Sections" link
 		And all sections are expanded
 
+	@skip-phantom
 	Scenario: Collapse link is not removed after last section of a course is deleted
 		Given I have a course with 1 section
 		And I navigate to the course overview page
diff --git a/cms/djangoapps/contentstore/features/subsection.feature b/cms/djangoapps/contentstore/features/subsection.feature
index 4b5f5b869d5..1be5f4aeb92 100644
--- a/cms/djangoapps/contentstore/features/subsection.feature
+++ b/cms/djangoapps/contentstore/features/subsection.feature
@@ -17,6 +17,7 @@ Feature: Create Subsection
     And I click to edit the subsection name
     Then I see the complete subsection name with a quote in the editor
 
+    @skip-phantom
     Scenario: Delete a subsection
     Given I have opened a new course section in Studio
     And I have added a new subsection
diff --git a/common/djangoapps/terrain/browser.py b/common/djangoapps/terrain/browser.py
index 8c2a8ba7a52..ddd39196de8 100644
--- a/common/djangoapps/terrain/browser.py
+++ b/common/djangoapps/terrain/browser.py
@@ -12,7 +12,8 @@ from django.core.management import call_command
 @before.harvest
 def initial_setup(server):
     # Launch the browser app (choose one of these below)
-    world.browser = Browser('chrome')
+    # world.browser = Browser('chrome')
+    world.browser = Browser('phantomjs')
     # world.browser = Browser('firefox')
 
 
-- 
GitLab