Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
5bd2390
Updated delete_project function is utils.py file.
Mar 17, 2016
732a493
Updated css selector on test_delete_sketches.py file.
Mar 17, 2016
d7c0d22
Updated create_sketch function is utils.py file.
Mar 24, 2016
200c686
Updated test_add_projectfile_direct function is test_sketch.py file.
Mar 24, 2016
e6bd116
Updated Firefox version to 45 in firefox_capabilities.yaml file.
Mar 24, 2016
c25b39d
Modified test_walkthrough.py to avoid random failures when testing pa…
Mar 31, 2016
8c4d236
Renamed P-Space-Jarvis attiny85.zip to P-Space-Jarvis-attiny85.zip.
Mar 31, 2016
be9b388
Updated test_compile_local_files function due to homepage changes.
Mar 31, 2016
bea5ae2
Updated functions that test upload functionality.
Mar 31, 2016
f709d18
Corrected assert statement in test_compile_local_files function.
Mar 31, 2016
2e586a1
Updated comments on function update_comment in disqus.py file.
Apr 5, 2016
daa8028
Added missing space in create_log function's arguments.
Apr 7, 2016
a49a574
Disqus comment in the last example of each library not logged in logf…
Apr 7, 2016
9046f0f
Updated dictionary of template strings used to generate the Disqus co…
Apr 7, 2016
ac01613
Updated function that handles Disqus library comments.
Apr 7, 2016
a07320d
Fixed issue: Disqus comment is not created when library has no examples.
Apr 13, 2016
ed135b4
Fixed issue: Disqus comment is not created when library has no examples.
Apr 13, 2016
0cbbc75
Fixed issue: Disqus comment is not created when library has no examples.
Apr 13, 2016
238867a
Fixed Firefox issue when running test_library_fetch.py test.
Apr 14, 2016
c80a28c
Removed redundant else condition from handle_library_comment function.
Apr 14, 2016
67215ee
Added parenthesis after if statements so that the code execution orde…
Apr 14, 2016
0d807d4
Removed unnecessary console.log used for debugging purpose.
Apr 14, 2016
b75a8a6
Added missing space after = .
Apr 14, 2016
42ee6b4
Added missing spaces after == .
Apr 14, 2016
d2583c3
Removed expected_condition from test_add_projectfile_direct function.
Apr 14, 2016
f75cd14
Added multiple functions that change project properties.
Apr 14, 2016
296a7aa
Updated create_project function and related tests.
Apr 14, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion codebender_testing/capabilities_firefox.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
# https://docs.saucelabs.com/reference/test-configuration

- browserName: "firefox"
version: 43
version: 45
public: "public restricted"
maxDuration: 10800
7 changes: 6 additions & 1 deletion codebender_testing/disqus.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ def update_comment(self, sketch, results, current_date, log_entry, openFailFlag,
library = library_match.group(1)

#Check if the currently compiled example belongs to the same library as the previous one.
# To do so we check if value of library is the same with self.last library value which is updated
# every time that we log the results of a compiled example.
if library != self.last_library:
library_to_comment = library

Expand All @@ -86,7 +88,7 @@ def update_comment(self, sketch, results, current_date, log_entry, openFailFlag,

return log_entry

def handle_library_comment(self, library, current_date, log):
def handle_library_comment(self, library, current_date, log, examples=True):
url = '/library/' + library
identifier = 'ident:' + url

Expand All @@ -108,7 +110,10 @@ def handle_library_comment(self, library, current_date, log):
thread=identifier)
if paginator:
comment_updated = False

new_message = self.messages['library'].replace('TEST_DATE', current_date)
if examples==False:
new_message = self.messages['library_no_examples'].replace('TEST_DATE', current_date)

for thread in paginator:

Expand Down
224 changes: 215 additions & 9 deletions codebender_testing/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,13 +409,22 @@ def delete_project(self, project_name):
self.open('/')
try:
created_project = self.get_element(By.LINK_TEXT, project_name)
delete_button_li = created_project.find_element_by_xpath('..')
delete_button = delete_button_li.find_element_by_css_selector('.delete-sketch')
delete_button_li = created_project.find_element_by_xpath('../..')
delete_button = delete_button_li.find_element_by_css_selector('.sketch-block-controls :nth-child(3)')
delete_button.click()
popup_delete_button = self.get_element(By.ID, 'deleteProjectButton')
popup_delete_button = self.get_element(By.CSS_SELECTOR, '#home-delete-sketch-modal :nth-child(4) :nth-child(2)')
popup_delete_button.click()
popup_delete_message = self.get_element(By.CSS_SELECTOR, '#home-delete-sketch-modal .modal-footer.delete-sketch-modal-footer .delete-sketch-modal-message.success')
assert popup_delete_message.text == "Sketch was deleted!"
popup_close_button = self.get_element(By.CSS_SELECTOR, '#home-delete-sketch-modal :nth-child(4) :nth-child(3)')
popup_close_button.click()
WebDriverWait(self.driver, VERIFY_TIMEOUT).until(
expected_conditions.invisibility_of_element_located(
(By.CSS_SELECTOR, "#home-delete-sketch-modal")
)
)
except:
pass
print "An action failed during deletion process of project:", project_name

def resume_log (self, logfile, compile_type, sketches):
"""Resume previous log, if any. Coves 3 cases:
Expand Down Expand Up @@ -508,7 +517,7 @@ def resume_log (self, logfile, compile_type, sketches):

return (urls_to_visit, log_entry, log_file, log_time)

def create_log (self, log_file, log_entry,compile_type):
def create_log (self, log_file, log_entry, compile_type):
# Dump the test results to `log_file`.
with open(log_file, 'w') as f:
f.write(jsondump(log_entry))
Expand All @@ -530,6 +539,12 @@ def open_all_libraries_and_examples(self, url, logfile):
tic = time.time()
for url in urls_to_visit:
self.open(url)
url_name = url.split('/')[-1]
name = self.get_element(By.CSS_SELECTOR, '#mycontainer h1 small').text
name = re.sub('[()]', '', name).split('.')[0]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain the intended behaviour?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We check the url that is actually open. We get the last part of the url EEPROM and check that is the same with the header element that appears in the page loaded EEPROM.
libraries

if (name != url_name):
print "Didn't open url: ", url

test_status = True
if library_re.match(url) and self.driver.current_url == 'https://codebender.cc/libraries':
test_status = False
Expand Down Expand Up @@ -608,6 +623,122 @@ def compile_sketch(self, url, boards, iframe=False, project_view=False):

return compilation_results

def comment_compile_libraries_examples(self, sketches, library_examples_dic={}, iframe=False, project_view=False,
logfile=None, compile_type='sketch', create_report=False, comment=False):

urls_to_visit, log_entry, log_file, log_time = self.resume_log(logfile, compile_type, sketches)

# Initialize DisqusWrapper.
disqus_wrapper = DisqusWrapper(log_time)
print "urls to visit:", urls_to_visit

print '\nCommenting and compiling:', len(urls_to_visit), 'libraries and examples.'

total_sketches = len(urls_to_visit)
tic = time.time()
library_re = re.compile(r'^.+/library/.+$')

for url in urls_to_visit:

if library_re.match(url):
library = url.split('/')[-1]
for key, value in library_examples_dic.iteritems():
if(key == library and len(value) == 0):
if logfile is None or not self.run_full_compile_tests:
toc = time.time()
continue

# Update Disqus comments.
current_date = strftime('%Y-%m-%d', log_time)
if comment and compile_type in ['library', 'target_library']:
library=key
examples=False
log_entry = disqus_wrapper.handle_library_comment(library, current_date, log_entry, examples)
self.create_log(log_file, log_entry, compile_type)
toc = time.time()
if (toc - tic) >= SAUCELABS_TIMEOUT_SECONDS:
print '\nStopping tests to avoid saucelabs timeout'
print 'Test duration:', int(toc - tic), 'sec'
return
else:
sketch = url
# Read the boards map in case current sketch/example requires a special board configuration.
boards = BOARDS_DB['default_boards']
url_fragments = urlparse(sketch)
if url_fragments.path in BOARDS_DB['special_boards']:
boards = BOARDS_DB['special_boards'][url_fragments.path]

if len(boards) > 0:
# Run Verify.
results = self.compile_sketch(sketch, boards, iframe=iframe, project_view=project_view)
else:
results = [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could initialize results to 'status': 'unsupported' until proven otherwise and remove the else condition

{
'status': 'unsupported'
}
]

"""If test is not running in full mode (-F option) or logfile is None
no logs are produced inside /logs directory and we continue with sketches
compilation.
"""
if logfile is None or not self.run_full_compile_tests:
toc = time.time()
continue

# Register current URL into log.
if sketch not in log_entry:
log_entry[sketch] = {}

test_status = '.'

# Log the compilation results.
openFailFlag = False
for result in results:
if result['status'] in ['success', 'fail', 'error'] and result['status'] not in log_entry[sketch]:
log_entry[sketch][result['status']] = []
if result['status'] == 'success':
log_entry[sketch]['success'].append(result['board'])
elif result['status'] == 'fail':
log_entry[sketch]['fail'].append(result['board'])
test_status = 'F'
elif result['status'] == 'open_fail':
log_entry[sketch]['open_fail'] = True
openFailFlag = True
test_status = 'O'
elif result['status'] == 'error':
log_entry[sketch]['error'].append({
'board': result['board'],
'error': result['message']
})
test_status = 'E'
elif result['status'] == 'unsupported':
log_entry[sketch]['unsupported'] = True
test_status = 'U'

# Update Disqus comments.
current_date = strftime('%Y-%m-%d', log_time)

if comment and compile_type in ['library', 'target_library']:
log_entry = disqus_wrapper.update_comment(sketch, results, current_date, log_entry, openFailFlag, total_sketches)

self.create_log(log_file, log_entry, compile_type)

# Display progress
sys.stdout.write(test_status)
sys.stdout.flush()

toc = time.time()
if (toc - tic) >= SAUCELABS_TIMEOUT_SECONDS:
print '\nStopping tests to avoid saucelabs timeout'
print 'Test duration:', int(toc - tic), 'sec'
return

# Generate a report if requested.
if compile_type != 'target_library' and create_report and self.run_full_compile_tests:
report_creator(compile_type, log_entry, log_file)
print '\nTest duration:', int(toc - tic), 'sec'

def compile_all_sketches(self, url, selector, **kwargs):
"""Compiles all sketches on the page at `url`. `selector` is a CSS selector
that should select all relevant <a> tags containing links to sketches.
Expand Down Expand Up @@ -695,13 +826,13 @@ def compile_sketches(self, sketches, iframe=False, project_view=False, logfile=N
log_entry[sketch]['unsupported'] = True
test_status = 'U'

self.create_log(log_file,log_entry, compile_type)

# Update Disqus comments.
current_date = strftime('%Y-%m-%d', log_time)
if comment and compile_type in ['library', 'target_library']:
log_entry = disqus_wrapper.update_comment(sketch, results, current_date, log_entry, openFailFlag, total_sketches)

self.create_log(log_file, log_entry, compile_type)

# Display progress
sys.stdout.write(test_status)
sys.stdout.flush()
Expand All @@ -726,11 +857,52 @@ def execute_script(self, script, *deps):
)
return self.driver.execute_script(script)

def create_sketch(self, name):
def create_sketch(self, privacy, name, description):
"""Creates a sketch with a given name"""
createSketchBtn = self.driver.find_element_by_id('create_sketch_btn')
createSketchBtn.click()
sketchHeading = self.get_element(By.ID, 'editor_heading_project_name')
WebDriverWait(self.driver, VERIFY_TIMEOUT).until(
expected_conditions.visibility_of_element_located(
(By.CSS_SELECTOR, "#create-sketch-modal")
)
)

self.change_privacy(privacy)

self.change_name(name)

self.change_short_description(description)

createBtn = self.get_element(By.ID, 'create-sketch-modal-action-button')
createBtn.click()
WebDriverWait(self.driver, VERIFY_TIMEOUT).until(
expected_conditions.invisibility_of_element_located(
(By.CSS_SELECTOR, "#editor-loading-screen")
)
)
WebDriverWait(self.driver, VERIFY_TIMEOUT).until(
expected_conditions.element_to_be_clickable(
(By.CSS_SELECTOR, "#editor_heading_project_name")
)
)

def change_privacy(self, privacy):
privateRadioButton = self.get_element(By.CSS_SELECTOR,'#create-sketch-modal-type-controls [value="public"]')
if privacy == 'private':
privateRadioButton = self.get_element(By.CSS_SELECTOR,'#create-sketch-modal-type-controls [value="private"]')
privateRadioButton.click()

def change_name(self, name):
print name
nameField = self.get_element(By.CSS_SELECTOR,'#create-sketch-modal .modal-body [id="create-sketch-name"')
print nameField
nameField.clear()
nameField.send_keys(name)
nameField.send_keys(Keys.ENTER)

def change_name_editor(self, name):
print "inside change name"
sketchHeading = self.driver.find_element_by_id('editor_heading_project_name')
sketchHeading.click()
renameInput = '#editor_heading_project_name input'
headingInput = self.get_element(By.CSS_SELECTOR, renameInput)
Expand All @@ -748,6 +920,40 @@ def create_sketch(self, name):
)
)

def change_short_description(self, description):
nameField = self.get_element(By.CSS_SELECTOR,'#create-sketch-modal-sort-description')
nameField.clear()
nameField.send_keys(description)
nameField.send_keys(Keys.ENTER)

def change_short_description_editor(self, description):
editDescription = self.get_element(By.CSS_SELECTOR,'.short-description-edit')
editDescription.click()
WebDriverWait(self.driver, VERIFY_TIMEOUT).until(
expected_conditions.visibility_of(
self.get_element(By.CSS_SELECTOR, '#editor-description-modal')
)
)
shortDescriptionField = self.get_element(By.CSS_SELECTOR,'#editor-description-modal .modal-body [id="short-description-modal-input"]')
shortDescriptionField.clear()
shortDescriptionField.send_keys(description)
shortDescriptionField.send_keys(Keys.ENTER)
saveButton = self.get_element(By.CSS_SELECTOR,'#editor-description-modal .modal-footer .btn-success')
saveButton.click()
WebDriverWait(self.driver, VERIFY_TIMEOUT).until(
expected_conditions.text_to_be_present_in_element(
(By.CSS_SELECTOR,'#editor-description-modal .modal-footer #editor-description-modal-message'), 'Sketch description saved.'
)
)
closeButton = self.get_element(By.CSS_SELECTOR,'#editor-description-modal .modal-footer .btn-danger')
closeButton.click()
WebDriverWait(self.driver, VERIFY_TIMEOUT).until(
expected_conditions.invisibility_of_element_located(
(By.CSS_SELECTOR, '#editor-description-modal')
)
)


def check_iframe(self):
"""Returns the contents of an iframe [project_name, user_name, sketch_contents]"""
self.driver.switch_to_frame(self.driver.find_element_by_tag_name('iframe'))
Expand Down
1 change: 1 addition & 0 deletions data/disqus_comments.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"library": "This library and its examples were tested on TEST_DATE with common Arduino boards. For more detailed information about the test results, please look at each example's comments.",
"library_no_examples": "This library was tested on TEST_DATE with common Arduino boards.",
"example_success": "This example was tested on TEST_DATE and it compiles on BOARDS_LIST.",
"example_fail": "This example was tested on TEST_DATE and it failed to compile on common Arduino boards.",
"example_unsupported": "This example is not known to compile with any of the codebender supported boards at least until TEST_DATE."
Expand Down
24 changes: 20 additions & 4 deletions tests/common/sketch/test_sketch.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from codebender_testing.utils import SeleniumTestCase
from codebender_testing.utils import SELECT_BOARD_SCRIPT
from codebender_testing.utils import throttle_compile
from selenium.webdriver.common.keys import Keys


# How long to wait before we give up on trying to assess the result of commands
Expand All @@ -25,7 +26,13 @@ class TestSketch(SeleniumTestCase):
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(TEST_PROJECT_NAME)
self.create_sketch('private' , 'project', 'short description')

def test_rename_project(self):
self.change_name_editor(TEST_PROJECT_NAME)

def test_change_short_description(self):
self.change_short_description_editor('decription')

def test_verify_code(self):
"""Ensures that we can compile code and see the success message."""
Expand Down Expand Up @@ -102,7 +109,7 @@ def test_clone_project(self):
clone_link.click()
project_name = self.get_element(By.ID, 'editor_heading_project_name')
# Here, I use `startswith` in case the user has a bunch of
# projects like "test_project copy copy copy" ...
# projects like "test_project copy copy copy"
assert project_name.text.startswith("%s copy" % TEST_PROJECT_NAME)

# Cleanup: delete the project we just created.
Expand All @@ -112,7 +119,16 @@ def test_add_projectfile_direct(self):
""" Tests that new file can be added to project using create-new-file
field """
self.open_project()

WebDriverWait(self.driver, VERIFY_TIMEOUT).until(
expected_conditions.invisibility_of_element_located(
(By.CSS_SELECTOR, "#editor-loading-screen")
)
)
WebDriverWait(self.driver, VERIFY_TIMEOUT).until(
expected_conditions.element_to_be_clickable(
(By.CSS_SELECTOR, "#newfile")
)
)
add_button = self.get_element(By.ID, 'newfile')
add_button.click()
WebDriverWait(self.driver, VERIFY_TIMEOUT).until(
Expand Down Expand Up @@ -160,4 +176,4 @@ def test_verify_deletion(self):
)

def test_remove_sketch(self):
self.delete_project(TEST_PROJECT_NAME)
self.delete_project(TEST_PROJECT_NAME)
Loading