From 8be53704b1526c1210e197844766fcfcfb2bac4b Mon Sep 17 00:00:00 2001
From: Christos Nianiakas <cnianiak@gmail.com>
Date: Thu, 21 Jul 2016 16:14:38 +0300
Subject: [PATCH 1/5] Added add/remove/rename file, remove sketch methods in
 CodebenderSeleniumBot class.

Will use the methods accross the tests.
---
 codebender_testing/utils.py | 68 ++++++++++++++++++++++++++++++++++---
 1 file changed, 63 insertions(+), 5 deletions(-)

diff --git a/codebender_testing/utils.py b/codebender_testing/utils.py
index e132d1a..c4077d3 100644
--- a/codebender_testing/utils.py
+++ b/codebender_testing/utils.py
@@ -20,6 +20,7 @@
 from selenium.webdriver.common.keys import Keys
 from selenium.webdriver.support import expected_conditions
 from selenium.webdriver.support.ui import WebDriverWait
+from selenium.common.exceptions import TimeoutException
 
 from codebender_testing.config import BASE_URL
 from codebender_testing.config import TIMEOUT
@@ -893,12 +894,16 @@ def create_sketch(self, privacy, name, description):
 
         createBtn = self.get_element(By.ID, 'create-sketch-modal-action-button')
         createBtn.click()
-
-        WebDriverWait(self.driver, TIMEOUT['LOCATE_ELEMENT']).until(
-            expected_conditions.visibility_of_element_located(
-                (By.CSS_SELECTOR, "#editor-loading-screen")
+        # Added in try-except block because if the loading screen disappears too quickly
+        # the explicit wait will through an exception
+        try:
+            WebDriverWait(self.driver, TIMEOUT['LOCATE_ELEMENT']).until(
+                expected_conditions.visibility_of_element_located(
+                    (By.CSS_SELECTOR, "#editor-loading-screen")
+                )
             )
-        )
+        except TimeoutException:
+            pass
         WebDriverWait(self.driver, TIMEOUT['LOCATE_ELEMENT']).until(
             expected_conditions.invisibility_of_element_located(
                 (By.CSS_SELECTOR, "#editor-loading-screen")
@@ -1006,6 +1011,59 @@ def switch_into_iframe(self, url):
         iframe = self.driver.find_elements_by_tag_name('iframe')[index]
         self.driver.switch_to_frame(iframe)
 
+    def create_file(self, filename):
+        """ Creates a file in editor """
+        self.get_element(By.ID, 'newfile').click()
+        WebDriverWait(self.driver, TIMEOUT['LOCATE_ELEMENT']).until(
+            expected_conditions.visibility_of_element_located(
+                (By.ID, 'creationModal'))
+        )
+        self.get_element(By.ID, 'createfield').send_keys(filename)
+        self.get_element(By.ID, 'createfield').send_keys(Keys.ENTER)
+        WebDriverWait(self.driver, TIMEOUT['LOCATE_ELEMENT']).until(
+            expected_conditions.invisibility_of_element_located(
+                (By.ID, 'creationModal'))
+        )
+
+    def remove_file(self, filename):
+        self.get_element(By.CSS_SELECTOR, '#files_list .filelist[data-name="{}"] + .delete-file-button'.format(filename)).click()
+        WebDriverWait(self.driver, TIMEOUT['LOCATE_ELEMENT']).until(
+            expected_conditions.visibility_of_element_located(
+                (By.ID, 'filedeleteModal'))
+        )
+        self.get_element(By.ID, 'filedeleteButton').click()
+        WebDriverWait(self.driver, TIMEOUT['LOCATE_ELEMENT']).until(
+            expected_conditions.invisibility_of_element_located(
+                (By.ID, 'filedeleteModal'))
+        )
+
+    def rename_file(self, old_filename, new_filename):
+        self.get_element(By.CSS_SELECTOR, '#files_list .filelist[data-name="{}"] ~ .rename-file-button'.format(old_filename)).click()
+        WebDriverWait(self.driver, TIMEOUT['LOCATE_ELEMENT']).until(
+            expected_conditions.visibility_of_element_located(
+                (By.ID, 'filenameModal'))
+        )
+        filename_input = self.get_element(By.ID, 'newFilename')
+        filename_input.clear()
+        filename_input.send_keys(new_filename)
+        filename_input.send_keys(Keys.ENTER)
+        WebDriverWait(self.driver, TIMEOUT['LOCATE_ELEMENT']).until(
+            expected_conditions.invisibility_of_element_located(
+                (By.ID, 'filenameModal'))
+        )
+
+    def remove_sketch_editor(self):
+        """ Removes the sketch from editor page """
+        self.get_element(By.ID, 'delete').click()
+        WebDriverWait(self.driver, TIMEOUT['LOCATE_ELEMENT']).until(
+            expected_conditions.visibility_of_element_located(
+                (By.ID, 'deletionModal'))
+        )
+        self.get_element(By.ID, 'deleteProjectButton').click()
+        WebDriverWait(self.driver, TIMEOUT['LOCATE_ELEMENT']).until(
+            expected_conditions.visibility_of_element_located(
+                (By.ID, 'main-container'))
+        )
 
 class SeleniumTestCase(CodebenderSeleniumBot):
     """Base class for all Selenium tests."""

From e7831e92c40ce80b6c2a447f1ec252f154010527 Mon Sep 17 00:00:00 2001
From: Christos Nianiakas <cnianiak@gmail.com>
Date: Thu, 21 Jul 2016 16:15:26 +0300
Subject: [PATCH 2/5] Added test for collaboration in editor.

Testing basic functionality of the editor when collaboration is enabled.
Tests can run in Firefox only due to its support for alert dialogs.
---
 bin/seleniumbender.py                     |  11 ++-
 tests/collaboration/__init__.py           |   0
 tests/collaboration/test_collaboration.py | 115 ++++++++++++++++++++++
 3 files changed, 125 insertions(+), 1 deletion(-)
 create mode 100644 tests/collaboration/__init__.py
 create mode 100644 tests/collaboration/test_collaboration.py

diff --git a/bin/seleniumbender.py b/bin/seleniumbender.py
index 8a6981f..76a0ad9 100755
--- a/bin/seleniumbender.py
+++ b/bin/seleniumbender.py
@@ -41,6 +41,8 @@ def run(self, operation, test=None, libraries=None):
             self.staging()
         elif operation == 'delete':
             self.delete()
+        elif operation == 'collaboration':
+            self.collaboration()
 
     def run_command(self, command):
         command = ' '.join(command)
@@ -158,6 +160,12 @@ def delete(self):
         if retval != 0:
             self.retval = retval
 
+    def collaboration(self):
+        command = self.create_command('collaboration')
+        retval = self.run_command(command)
+        if retval != 0:
+            self.retval = retval
+
 OPERATIONS = {
     'common':'\tTest site common functionality',
     'libraries': 'Visit all libraries and their examples',
@@ -167,7 +175,8 @@ def delete(self):
     'noplugin': 'Run tests without app/plugin installed',
     'walkthrough': 'Run tests for walkthrough',
     'staging': '\tRun tests for staging only',
-    'delete': '\tDelete all sketches from test user'
+    'delete': '\tDelete all sketches from test user',
+    'collaboration': 'Run tests for collaboration'
 }
 
 TARGETS = {
diff --git a/tests/collaboration/__init__.py b/tests/collaboration/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/collaboration/test_collaboration.py b/tests/collaboration/test_collaboration.py
new file mode 100644
index 0000000..9d6c414
--- /dev/null
+++ b/tests/collaboration/test_collaboration.py
@@ -0,0 +1,115 @@
+import pytest
+from selenium.webdriver.common.by import By
+from selenium.webdriver.common.keys import Keys
+from selenium.webdriver.support.ui import WebDriverWait
+from selenium.webdriver.support import expected_conditions
+from selenium.webdriver.common.action_chains import ActionChains
+from selenium.webdriver.common.alert import Alert
+from codebender_testing.utils import SeleniumTestCase
+from codebender_testing.config import TIMEOUT
+import time
+
+TEST_SKETCH = 'test_collaboration'
+TEST_FILE = 'test.h'
+TEST_EMPTY_FILE = 'empty.h'
+TEST_RENAME_FILE = 'rename.h'
+TEST_RENAMED_FILE = 'renamed.h'
+TEST_INPUT = '// test input'
+
+class TestCollaboration(SeleniumTestCase):
+    ''' Opens a new tab in the browser '''
+    def open_tab(self, url):
+        self.execute_script('window.open("{}")'.format(url))
+
+    ''' Closes current tab in the browser '''
+    def close_tab(self):
+        self.execute_script('window.close()')
+
+    ''' Switches between tabs in the browser '''
+    def switch_window(self, index):
+        window = self.driver.window_handles[index]
+        self.driver.switch_to.window(window)
+
+    @pytest.fixture(scope="class", autouse=True)
+    def create_test_project(self, tester_login):
+        """Makes sure we are logged in and have a project open before
+        performing any of these tests."""
+        self.create_sketch('public' , TEST_SKETCH, '')
+
+    def test_open_tab(self):
+        self.sketch_url = self.execute_script('return location.href')
+        self.open_tab(self.sketch_url)
+        WebDriverWait(self.driver, TIMEOUT['LOCATE_ELEMENT']).until(
+            expected_conditions.invisibility_of_element_located(
+                (By.CSS_SELECTOR, "#editor-loading-screen")
+            )
+        )
+        WebDriverWait(self.driver, TIMEOUT['LOCATE_ELEMENT']).until(
+            expected_conditions.element_to_be_clickable(
+                (By.CSS_SELECTOR, "#editor_heading_project_name")
+            )
+        )
+
+    def test_create_file(self):
+        self.switch_window(0)
+        self.create_file(TEST_FILE)
+
+    def test_check_created_file(self):
+        self.switch_window(1)
+        test_file = self.get_element(By.CSS_SELECTOR, '#files_list .filelist[data-name="{}"]'.format(TEST_FILE))
+        filename = test_file.text.strip()
+        assert filename == TEST_FILE
+        test_file.click()
+        self.execute_script('editor.aceEditor.setValue("{}");'.format(TEST_INPUT), 'editor')
+
+    def test_check_contents_change(self):
+        self.switch_window(0)
+        while self.execute_script('return editor.aceEditor.getValue();') != TEST_INPUT:
+            time.sleep(1) # Wait for editor to sync
+        test_input = self.execute_script('return editor.aceEditor.getValue();')
+        assert TEST_INPUT == test_input
+
+    def test_create_and_delete_file(self):
+        self.switch_window(0)
+        self.create_file(TEST_EMPTY_FILE)
+        self.switch_window(1)
+        test_file = self.get_element(By.CSS_SELECTOR, '#files_list .filelist[data-name="{}"]'.format(TEST_EMPTY_FILE))
+        filename = test_file.text.strip()
+        assert filename == TEST_EMPTY_FILE
+        test_file.click()
+        self.execute_script('editor.aceEditor.setValue("{}");'.format(TEST_INPUT), 'editor')
+        self.remove_file(filename)
+        self.switch_window(0)
+        WebDriverWait(self.driver, TIMEOUT['LOCATE_ELEMENT']).until(
+            expected_conditions.alert_is_present()
+        )
+        Alert(self.driver).dismiss()
+
+    def test_check_deleted_file(self):
+        self.switch_window(0)
+        deleted_file = self.driver.find_elements_by_css_selector('#files_list .filelist[data-name="{}"]'.format(TEST_EMPTY_FILE))
+        assert len(deleted_file) == 0
+        self.create_file(TEST_EMPTY_FILE)
+        empty_contents = self.execute_script('return editor.aceEditor.getValue();', 'editor')
+        assert empty_contents == ''
+
+    def test_rename_file(self):
+        self.switch_window(1)
+        self.create_file(TEST_RENAME_FILE)
+        self.execute_script('editor.aceEditor.setValue("int a = 1;");', 'editor')
+        self.execute_script('editor.aceEditor.session.selection.moveCursorToPosition({row: 0, column: 3}); editor.aceEditor.session.selection.clearSelection();', 'editor')
+        self.switch_window(0)
+        self.get_element(By.CSS_SELECTOR, '#files_list .filelist[data-name="{}"]'.format(TEST_RENAME_FILE)).click()
+        self.rename_file(TEST_RENAME_FILE, TEST_RENAMED_FILE)
+        self.switch_window(1)
+        self.get_element(By.CSS_SELECTOR, '#files_list .filelist[data-name="{}"]'.format(TEST_RENAMED_FILE))
+
+    def test_remove_sketch(self):
+        self.switch_window(1)
+        self.remove_sketch_editor()
+        self.switch_window(0)
+        WebDriverWait(self.driver, TIMEOUT['LOCATE_ELEMENT']).until(
+            expected_conditions.alert_is_present()
+        )
+        Alert(self.driver).dismiss()
+        self.logout()

From cd9ee4204e6cc4ab2dbf5d6d98e539a92564b1ce Mon Sep 17 00:00:00 2001
From: Christos Nianiakas <cnianiak@gmail.com>
Date: Thu, 21 Jul 2016 16:48:02 +0300
Subject: [PATCH 3/5] Added collaboration tests in common cron job.

---
 bin/cron/common | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/bin/cron/common b/bin/cron/common
index ff0d96a..4626d8c 100755
--- a/bin/cron/common
+++ b/bin/cron/common
@@ -11,3 +11,5 @@ python seleniumbender.py walkthrough --target=live --saucelabs --capabilities=ca
 # noplugin
 python seleniumbender.py noplugin --target=live --saucelabs --capabilities=capabilities_firefox.yaml --config=config.cfg
 python seleniumbender.py noplugin --target=live --saucelabs --capabilities=capabilities_chrome.yaml --config=config.cfg
+# collaboration
+python seleniumbender.py collaboration --target=live --saucelabs --capabilities=capabilities_firefox.yaml --config=config.cfg

From 50b62ea68fa3ff8979badeb49d1971b3b7255b4d Mon Sep 17 00:00:00 2001
From: Christos Nianiakas <cnianiak@gmail.com>
Date: Thu, 21 Jul 2016 16:48:46 +0300
Subject: [PATCH 4/5] Using Windows 10 in tests for walkthrough.

---
 bin/seleniumbender.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bin/seleniumbender.py b/bin/seleniumbender.py
index 76a0ad9..fcf224a 100755
--- a/bin/seleniumbender.py
+++ b/bin/seleniumbender.py
@@ -187,7 +187,7 @@ def collaboration(self):
 
 PLATFORMS = {
     'Linux': 'X11; Ubuntu; Linux x86_64',
-    'Windows 7': 'Windows NT 6.1',
+    'Windows 10': 'Windows NT 10.0',
     'OS X 10.11': 'Macintosh; Intel Mac OS X 10_11_1'
 }
 USER_AGENTS = {}

From 950627e3a551b662a8fee27d73a39320a9b6b4fc Mon Sep 17 00:00:00 2001
From: Christos Nianiakas <cnianiak@gmail.com>
Date: Thu, 21 Jul 2016 17:53:08 +0300
Subject: [PATCH 5/5] Fixed assignment of global variable.

Needed 'global' prefix before the assignment.
---
 codebender_testing/config.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/codebender_testing/config.py b/codebender_testing/config.py
index df5f36d..d1b0967 100644
--- a/codebender_testing/config.py
+++ b/codebender_testing/config.py
@@ -147,6 +147,7 @@ def create_webdriver(command_executor, desired_capabilities):
     browser_profile = None
     browser_profile_path = None
 
+    global SELENIUM_BROWSER
     SELENIUM_BROWSER = browser_name
 
     if browser_name == "chrome":