Skip to content

Commit fcd5a0c

Browse files
committed
Merge pull request #26 from codebendercc/home_page_redesign_tests_refactor
Home page redesign tests refactor and bugs fixing of logs, comments, reports creation.
2 parents 1e5c5d9 + 296a7aa commit fcd5a0c

File tree

13 files changed

+393
-53
lines changed

13 files changed

+393
-53
lines changed

codebender_testing/capabilities_firefox.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
# https://docs.saucelabs.com/reference/test-configuration
88

99
- browserName: "firefox"
10-
version: 43
10+
version: 45
1111
public: "public restricted"
1212
maxDuration: 10800

codebender_testing/disqus.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ def update_comment(self, sketch, results, current_date, log_entry, openFailFlag,
7272
library = library_match.group(1)
7373

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

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

8789
return log_entry
8890

89-
def handle_library_comment(self, library, current_date, log):
91+
def handle_library_comment(self, library, current_date, log, examples=True):
9092
url = '/library/' + library
9193
identifier = 'ident:' + url
9294

@@ -108,7 +110,10 @@ def handle_library_comment(self, library, current_date, log):
108110
thread=identifier)
109111
if paginator:
110112
comment_updated = False
113+
111114
new_message = self.messages['library'].replace('TEST_DATE', current_date)
115+
if examples==False:
116+
new_message = self.messages['library_no_examples'].replace('TEST_DATE', current_date)
112117

113118
for thread in paginator:
114119

codebender_testing/utils.py

Lines changed: 215 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -409,13 +409,22 @@ def delete_project(self, project_name):
409409
self.open('/')
410410
try:
411411
created_project = self.get_element(By.LINK_TEXT, project_name)
412-
delete_button_li = created_project.find_element_by_xpath('..')
413-
delete_button = delete_button_li.find_element_by_css_selector('.delete-sketch')
412+
delete_button_li = created_project.find_element_by_xpath('../..')
413+
delete_button = delete_button_li.find_element_by_css_selector('.sketch-block-controls :nth-child(3)')
414414
delete_button.click()
415-
popup_delete_button = self.get_element(By.ID, 'deleteProjectButton')
415+
popup_delete_button = self.get_element(By.CSS_SELECTOR, '#home-delete-sketch-modal :nth-child(4) :nth-child(2)')
416416
popup_delete_button.click()
417+
popup_delete_message = self.get_element(By.CSS_SELECTOR, '#home-delete-sketch-modal .modal-footer.delete-sketch-modal-footer .delete-sketch-modal-message.success')
418+
assert popup_delete_message.text == "Sketch was deleted!"
419+
popup_close_button = self.get_element(By.CSS_SELECTOR, '#home-delete-sketch-modal :nth-child(4) :nth-child(3)')
420+
popup_close_button.click()
421+
WebDriverWait(self.driver, VERIFY_TIMEOUT).until(
422+
expected_conditions.invisibility_of_element_located(
423+
(By.CSS_SELECTOR, "#home-delete-sketch-modal")
424+
)
425+
)
417426
except:
418-
pass
427+
print "An action failed during deletion process of project:", project_name
419428

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

509518
return (urls_to_visit, log_entry, log_file, log_time)
510519

511-
def create_log (self, log_file, log_entry,compile_type):
520+
def create_log (self, log_file, log_entry, compile_type):
512521
# Dump the test results to `log_file`.
513522
with open(log_file, 'w') as f:
514523
f.write(jsondump(log_entry))
@@ -530,6 +539,12 @@ def open_all_libraries_and_examples(self, url, logfile):
530539
tic = time.time()
531540
for url in urls_to_visit:
532541
self.open(url)
542+
url_name = url.split('/')[-1]
543+
name = self.get_element(By.CSS_SELECTOR, '#mycontainer h1 small').text
544+
name = re.sub('[()]', '', name).split('.')[0]
545+
if (name != url_name):
546+
print "Didn't open url: ", url
547+
533548
test_status = True
534549
if library_re.match(url) and self.driver.current_url == 'https://codebender.cc/libraries':
535550
test_status = False
@@ -608,6 +623,122 @@ def compile_sketch(self, url, boards, iframe=False, project_view=False):
608623

609624
return compilation_results
610625

626+
def comment_compile_libraries_examples(self, sketches, library_examples_dic={}, iframe=False, project_view=False,
627+
logfile=None, compile_type='sketch', create_report=False, comment=False):
628+
629+
urls_to_visit, log_entry, log_file, log_time = self.resume_log(logfile, compile_type, sketches)
630+
631+
# Initialize DisqusWrapper.
632+
disqus_wrapper = DisqusWrapper(log_time)
633+
print "urls to visit:", urls_to_visit
634+
635+
print '\nCommenting and compiling:', len(urls_to_visit), 'libraries and examples.'
636+
637+
total_sketches = len(urls_to_visit)
638+
tic = time.time()
639+
library_re = re.compile(r'^.+/library/.+$')
640+
641+
for url in urls_to_visit:
642+
643+
if library_re.match(url):
644+
library = url.split('/')[-1]
645+
for key, value in library_examples_dic.iteritems():
646+
if(key == library and len(value) == 0):
647+
if logfile is None or not self.run_full_compile_tests:
648+
toc = time.time()
649+
continue
650+
651+
# Update Disqus comments.
652+
current_date = strftime('%Y-%m-%d', log_time)
653+
if comment and compile_type in ['library', 'target_library']:
654+
library=key
655+
examples=False
656+
log_entry = disqus_wrapper.handle_library_comment(library, current_date, log_entry, examples)
657+
self.create_log(log_file, log_entry, compile_type)
658+
toc = time.time()
659+
if (toc - tic) >= SAUCELABS_TIMEOUT_SECONDS:
660+
print '\nStopping tests to avoid saucelabs timeout'
661+
print 'Test duration:', int(toc - tic), 'sec'
662+
return
663+
else:
664+
sketch = url
665+
# Read the boards map in case current sketch/example requires a special board configuration.
666+
boards = BOARDS_DB['default_boards']
667+
url_fragments = urlparse(sketch)
668+
if url_fragments.path in BOARDS_DB['special_boards']:
669+
boards = BOARDS_DB['special_boards'][url_fragments.path]
670+
671+
if len(boards) > 0:
672+
# Run Verify.
673+
results = self.compile_sketch(sketch, boards, iframe=iframe, project_view=project_view)
674+
else:
675+
results = [
676+
{
677+
'status': 'unsupported'
678+
}
679+
]
680+
681+
"""If test is not running in full mode (-F option) or logfile is None
682+
no logs are produced inside /logs directory and we continue with sketches
683+
compilation.
684+
"""
685+
if logfile is None or not self.run_full_compile_tests:
686+
toc = time.time()
687+
continue
688+
689+
# Register current URL into log.
690+
if sketch not in log_entry:
691+
log_entry[sketch] = {}
692+
693+
test_status = '.'
694+
695+
# Log the compilation results.
696+
openFailFlag = False
697+
for result in results:
698+
if result['status'] in ['success', 'fail', 'error'] and result['status'] not in log_entry[sketch]:
699+
log_entry[sketch][result['status']] = []
700+
if result['status'] == 'success':
701+
log_entry[sketch]['success'].append(result['board'])
702+
elif result['status'] == 'fail':
703+
log_entry[sketch]['fail'].append(result['board'])
704+
test_status = 'F'
705+
elif result['status'] == 'open_fail':
706+
log_entry[sketch]['open_fail'] = True
707+
openFailFlag = True
708+
test_status = 'O'
709+
elif result['status'] == 'error':
710+
log_entry[sketch]['error'].append({
711+
'board': result['board'],
712+
'error': result['message']
713+
})
714+
test_status = 'E'
715+
elif result['status'] == 'unsupported':
716+
log_entry[sketch]['unsupported'] = True
717+
test_status = 'U'
718+
719+
# Update Disqus comments.
720+
current_date = strftime('%Y-%m-%d', log_time)
721+
722+
if comment and compile_type in ['library', 'target_library']:
723+
log_entry = disqus_wrapper.update_comment(sketch, results, current_date, log_entry, openFailFlag, total_sketches)
724+
725+
self.create_log(log_file, log_entry, compile_type)
726+
727+
# Display progress
728+
sys.stdout.write(test_status)
729+
sys.stdout.flush()
730+
731+
toc = time.time()
732+
if (toc - tic) >= SAUCELABS_TIMEOUT_SECONDS:
733+
print '\nStopping tests to avoid saucelabs timeout'
734+
print 'Test duration:', int(toc - tic), 'sec'
735+
return
736+
737+
# Generate a report if requested.
738+
if compile_type != 'target_library' and create_report and self.run_full_compile_tests:
739+
report_creator(compile_type, log_entry, log_file)
740+
print '\nTest duration:', int(toc - tic), 'sec'
741+
611742
def compile_all_sketches(self, url, selector, **kwargs):
612743
"""Compiles all sketches on the page at `url`. `selector` is a CSS selector
613744
that should select all relevant <a> tags containing links to sketches.
@@ -695,13 +826,13 @@ def compile_sketches(self, sketches, iframe=False, project_view=False, logfile=N
695826
log_entry[sketch]['unsupported'] = True
696827
test_status = 'U'
697828

698-
self.create_log(log_file,log_entry, compile_type)
699-
700829
# Update Disqus comments.
701830
current_date = strftime('%Y-%m-%d', log_time)
702831
if comment and compile_type in ['library', 'target_library']:
703832
log_entry = disqus_wrapper.update_comment(sketch, results, current_date, log_entry, openFailFlag, total_sketches)
704833

834+
self.create_log(log_file, log_entry, compile_type)
835+
705836
# Display progress
706837
sys.stdout.write(test_status)
707838
sys.stdout.flush()
@@ -726,11 +857,52 @@ def execute_script(self, script, *deps):
726857
)
727858
return self.driver.execute_script(script)
728859

729-
def create_sketch(self, name):
860+
def create_sketch(self, privacy, name, description):
730861
"""Creates a sketch with a given name"""
731862
createSketchBtn = self.driver.find_element_by_id('create_sketch_btn')
732863
createSketchBtn.click()
733-
sketchHeading = self.get_element(By.ID, 'editor_heading_project_name')
864+
WebDriverWait(self.driver, VERIFY_TIMEOUT).until(
865+
expected_conditions.visibility_of_element_located(
866+
(By.CSS_SELECTOR, "#create-sketch-modal")
867+
)
868+
)
869+
870+
self.change_privacy(privacy)
871+
872+
self.change_name(name)
873+
874+
self.change_short_description(description)
875+
876+
createBtn = self.get_element(By.ID, 'create-sketch-modal-action-button')
877+
createBtn.click()
878+
WebDriverWait(self.driver, VERIFY_TIMEOUT).until(
879+
expected_conditions.invisibility_of_element_located(
880+
(By.CSS_SELECTOR, "#editor-loading-screen")
881+
)
882+
)
883+
WebDriverWait(self.driver, VERIFY_TIMEOUT).until(
884+
expected_conditions.element_to_be_clickable(
885+
(By.CSS_SELECTOR, "#editor_heading_project_name")
886+
)
887+
)
888+
889+
def change_privacy(self, privacy):
890+
privateRadioButton = self.get_element(By.CSS_SELECTOR,'#create-sketch-modal-type-controls [value="public"]')
891+
if privacy == 'private':
892+
privateRadioButton = self.get_element(By.CSS_SELECTOR,'#create-sketch-modal-type-controls [value="private"]')
893+
privateRadioButton.click()
894+
895+
def change_name(self, name):
896+
print name
897+
nameField = self.get_element(By.CSS_SELECTOR,'#create-sketch-modal .modal-body [id="create-sketch-name"')
898+
print nameField
899+
nameField.clear()
900+
nameField.send_keys(name)
901+
nameField.send_keys(Keys.ENTER)
902+
903+
def change_name_editor(self, name):
904+
print "inside change name"
905+
sketchHeading = self.driver.find_element_by_id('editor_heading_project_name')
734906
sketchHeading.click()
735907
renameInput = '#editor_heading_project_name input'
736908
headingInput = self.get_element(By.CSS_SELECTOR, renameInput)
@@ -748,6 +920,40 @@ def create_sketch(self, name):
748920
)
749921
)
750922

923+
def change_short_description(self, description):
924+
nameField = self.get_element(By.CSS_SELECTOR,'#create-sketch-modal-sort-description')
925+
nameField.clear()
926+
nameField.send_keys(description)
927+
nameField.send_keys(Keys.ENTER)
928+
929+
def change_short_description_editor(self, description):
930+
editDescription = self.get_element(By.CSS_SELECTOR,'.short-description-edit')
931+
editDescription.click()
932+
WebDriverWait(self.driver, VERIFY_TIMEOUT).until(
933+
expected_conditions.visibility_of(
934+
self.get_element(By.CSS_SELECTOR, '#editor-description-modal')
935+
)
936+
)
937+
shortDescriptionField = self.get_element(By.CSS_SELECTOR,'#editor-description-modal .modal-body [id="short-description-modal-input"]')
938+
shortDescriptionField.clear()
939+
shortDescriptionField.send_keys(description)
940+
shortDescriptionField.send_keys(Keys.ENTER)
941+
saveButton = self.get_element(By.CSS_SELECTOR,'#editor-description-modal .modal-footer .btn-success')
942+
saveButton.click()
943+
WebDriverWait(self.driver, VERIFY_TIMEOUT).until(
944+
expected_conditions.text_to_be_present_in_element(
945+
(By.CSS_SELECTOR,'#editor-description-modal .modal-footer #editor-description-modal-message'), 'Sketch description saved.'
946+
)
947+
)
948+
closeButton = self.get_element(By.CSS_SELECTOR,'#editor-description-modal .modal-footer .btn-danger')
949+
closeButton.click()
950+
WebDriverWait(self.driver, VERIFY_TIMEOUT).until(
951+
expected_conditions.invisibility_of_element_located(
952+
(By.CSS_SELECTOR, '#editor-description-modal')
953+
)
954+
)
955+
956+
751957
def check_iframe(self):
752958
"""Returns the contents of an iframe [project_name, user_name, sketch_contents]"""
753959
self.driver.switch_to_frame(self.driver.find_element_by_tag_name('iframe'))

data/disqus_comments.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"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.",
3+
"library_no_examples": "This library was tested on TEST_DATE with common Arduino boards.",
34
"example_success": "This example was tested on TEST_DATE and it compiles on BOARDS_LIST.",
45
"example_fail": "This example was tested on TEST_DATE and it failed to compile on common Arduino boards.",
56
"example_unsupported": "This example is not known to compile with any of the codebender supported boards at least until TEST_DATE."

tests/common/sketch/test_sketch.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from codebender_testing.utils import SeleniumTestCase
99
from codebender_testing.utils import SELECT_BOARD_SCRIPT
1010
from codebender_testing.utils import throttle_compile
11+
from selenium.webdriver.common.keys import Keys
1112

1213

1314
# How long to wait before we give up on trying to assess the result of commands
@@ -25,7 +26,13 @@ class TestSketch(SeleniumTestCase):
2526
def create_test_project(self, tester_login):
2627
"""Makes sure we are logged in and have a project open before
2728
performing any of these tests."""
28-
self.create_sketch(TEST_PROJECT_NAME)
29+
self.create_sketch('private' , 'project', 'short description')
30+
31+
def test_rename_project(self):
32+
self.change_name_editor(TEST_PROJECT_NAME)
33+
34+
def test_change_short_description(self):
35+
self.change_short_description_editor('decription')
2936

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

108115
# Cleanup: delete the project we just created.
@@ -112,7 +119,16 @@ def test_add_projectfile_direct(self):
112119
""" Tests that new file can be added to project using create-new-file
113120
field """
114121
self.open_project()
115-
122+
WebDriverWait(self.driver, VERIFY_TIMEOUT).until(
123+
expected_conditions.invisibility_of_element_located(
124+
(By.CSS_SELECTOR, "#editor-loading-screen")
125+
)
126+
)
127+
WebDriverWait(self.driver, VERIFY_TIMEOUT).until(
128+
expected_conditions.element_to_be_clickable(
129+
(By.CSS_SELECTOR, "#newfile")
130+
)
131+
)
116132
add_button = self.get_element(By.ID, 'newfile')
117133
add_button.click()
118134
WebDriverWait(self.driver, VERIFY_TIMEOUT).until(
@@ -160,4 +176,4 @@ def test_verify_deletion(self):
160176
)
161177

162178
def test_remove_sketch(self):
163-
self.delete_project(TEST_PROJECT_NAME)
179+
self.delete_project(TEST_PROJECT_NAME)

0 commit comments

Comments
 (0)