Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
7818b709
Commit
7818b709
authored
Oct 13, 2015
by
Jesse Zoldak
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[WIP] headless bokchoy
parent
034ac1c8
Show whitespace changes
Inline
Side-by-side
Showing
32 changed files
with
321 additions
and
21 deletions
+321
-21
common/test/acceptance/pages/lms/course_nav.py
+1
-1
common/test/acceptance/pages/lms/discovery.py
+1
-0
common/test/acceptance/pages/lms/discussion.py
+1
-0
common/test/acceptance/pages/lms/edxnotes.py
+1
-0
common/test/acceptance/pages/lms/fields.py
+2
-0
common/test/acceptance/pages/lms/instructor_dashboard.py
+4
-4
common/test/acceptance/pages/lms/teams.py
+1
-0
common/test/acceptance/pages/studio/import_export.py
+2
-0
common/test/acceptance/pages/studio/library.py
+1
-0
common/test/acceptance/pages/studio/overview.py
+1
-0
common/test/acceptance/pages/studio/settings_certificates.py
+2
-0
common/test/acceptance/pages/studio/settings_group_configurations.py
+1
-0
common/test/acceptance/pages/studio/textbooks.py
+1
-0
common/test/acceptance/tests/discussion/test_cohort_management.py
+1
-0
common/test/acceptance/tests/discussion/test_cohorts.py
+2
-0
common/test/acceptance/tests/discussion/test_discussion.py
+1
-0
common/test/acceptance/tests/helpers.py
+1
-0
common/test/acceptance/tests/lms/test_account_settings.py
+1
-0
common/test/acceptance/tests/lms/test_lms.py
+2
-2
common/test/acceptance/tests/lms/test_lms_cohorted_courseware_search.py
+1
-1
common/test/acceptance/tests/lms/test_lms_course_discovery.py
+1
-0
common/test/acceptance/tests/lms/test_lms_split_test_courseware_search.py
+1
-1
common/test/acceptance/tests/lms/test_lms_user_preview.py
+2
-0
common/test/acceptance/tests/lms/test_teams.py
+1
-0
common/test/acceptance/tests/studio/test_studio_asset.py
+5
-2
common/test/acceptance/tests/studio/test_studio_home.py
+1
-0
common/test/acceptance/tests/studio/test_studio_library.py
+1
-1
common/test/acceptance/tests/studio/test_studio_rerun.py
+3
-2
common/test/acceptance/tests/test_cohorted_courseware.py
+1
-0
common/test/acceptance/tests/video/test_video_module.py
+1
-0
scripts/generic-ci-tests.sh
+7
-7
scripts/htmlwriter.py
+269
-0
No files found.
common/test/acceptance/pages/lms/course_nav.py
View file @
7818b709
...
...
@@ -69,7 +69,7 @@ class CourseNavPage(PageObject):
Example:
go_to_section("Week 1", "Lesson 1")
"""
assert
False
,
"Go to section fails in phantomjs"
# For test stability, disable JQuery animations (opening / closing menus)
self
.
browser
.
execute_script
(
"jQuery.fx.off = true;"
)
...
...
common/test/acceptance/pages/lms/discovery.py
View file @
7818b709
...
...
@@ -21,6 +21,7 @@ class CourseDiscoveryPage(PageObject):
loading_css
=
"#loading-indicator"
courses_css
=
'.courses-listing'
assert
False
,
"Another loading indicator page"
return
self
.
q
(
css
=
courses_css
)
.
visible
\
and
self
.
q
(
css
=
loading_css
)
.
present
\
and
not
self
.
q
(
css
=
loading_css
)
.
visible
...
...
common/test/acceptance/pages/lms/discussion.py
View file @
7818b709
...
...
@@ -101,6 +101,7 @@ class DiscussionThreadPage(PageObject, DiscussionPageMixin):
Clicks the add response button and ensures that the response text
field receives focus
"""
assert
False
,
"Needs click add response button"
self
.
_find_within
(
".add-response-btn"
)
.
first
.
click
()
EmptyPromise
(
lambda
:
self
.
_find_within
(
".discussion-reply-new textarea:focus"
)
.
present
,
...
...
common/test/acceptance/pages/lms/edxnotes.py
View file @
7818b709
...
...
@@ -532,6 +532,7 @@ class EdxNoteHighlight(NoteChild):
Creates selection for the element and clicks `add note` button.
"""
ActionChains
(
self
.
browser
)
.
double_click
(
self
.
element
)
.
release
()
.
perform
()
assert
False
,
"Needs to wait for adder visibility"
self
.
wait_for_adder_visibility
()
self
.
q
(
css
=
self
.
_bounded_selector
(
self
.
ADDER_SELECTOR
))
.
first
.
click
()
self
.
wait_for_editor_visibility
()
...
...
common/test/acceptance/pages/lms/fields.py
View file @
7818b709
...
...
@@ -194,6 +194,8 @@ class FieldsMixin(object):
"""
Get or set the value in a dropdown field.
"""
assert
False
,
"This test uses value_for_dropdown_field"
self
.
wait_for_field
(
field_id
)
self
.
make_field_editable
(
field_id
)
...
...
common/test/acceptance/pages/lms/instructor_dashboard.py
View file @
7818b709
...
...
@@ -519,12 +519,11 @@ class CohortManagementSection(PageObject):
"""
Uploads a file with cohort assignment information.
"""
assert
False
,
"This has a file upload and needs a browser"
# Toggle on the CSV upload section.
cvs_upload_toggle_css
=
'.toggle-cohort-management-secondary'
self
.
wait_for_element_visibility
(
cvs_upload_toggle_css
,
"Wait for csv upload link to appear"
)
cvs_upload_toggle
=
self
.
q
(
css
=
self
.
_bounded_selector
(
cvs_upload_toggle_css
))
.
first
if
cvs_upload_toggle
:
cvs_upload_toggle
.
click
()
cvs_upload_toggle
=
self
.
q
(
css
=
self
.
_bounded_selector
(
cvs_upload_toggle_css
))
.
first
.
click
()
self
.
wait_for_element_visibility
(
self
.
_bounded_selector
(
self
.
csv_browse_button_selector_css
),
'File upload link visible'
...
...
@@ -532,7 +531,8 @@ class CohortManagementSection(PageObject):
path
=
InstructorDashboardPage
.
get_asset_path
(
filename
)
file_input
=
self
.
q
(
css
=
self
.
_bounded_selector
(
self
.
csv_browse_button_selector_css
))
.
results
[
0
]
file_input
.
send_keys
(
path
)
self
.
q
(
css
=
self
.
_bounded_selector
(
self
.
csv_upload_button_selector_css
))
.
first
.
click
()
upload_file_button
=
self
.
q
(
css
=
self
.
_bounded_selector
(
self
.
csv_upload_button_selector_css
))
.
first
.
results
[
0
]
upload_file_button
.
click
()
@property
def
is_cohorted
(
self
):
...
...
common/test/acceptance/pages/lms/teams.py
View file @
7818b709
...
...
@@ -135,6 +135,7 @@ class TeamsPage(CoursePage, BreadcrumbsMixin):
@property
def
warning_message
(
self
):
"""Return the text of the team warning message."""
assert
False
,
"Warning message fails under phantomjs"
return
self
.
q
(
css
=
'.warning'
)
.
results
[
0
]
.
text
...
...
common/test/acceptance/pages/studio/import_export.py
View file @
7818b709
...
...
@@ -232,6 +232,7 @@ class ImportMixin(object):
"""
Wait for the upload to be confirmed.
"""
assert
False
,
"Needs to wait for upload"
EmptyPromise
(
self
.
is_upload_finished
,
'Upload Finished'
,
timeout
=
30
)
.
fulfill
()
def
is_filename_error_showing
(
self
):
...
...
@@ -267,6 +268,7 @@ class ImportMixin(object):
"""
Wait for the upload field to display an error.
"""
assert
False
,
"Needs to wait for filename error"
EmptyPromise
(
self
.
is_filename_error_showing
,
'Upload Error Displayed'
,
timeout
=
30
)
.
fulfill
()
def
finished_target_url
(
self
):
...
...
common/test/acceptance/pages/studio/library.py
View file @
7818b709
...
...
@@ -98,6 +98,7 @@ class LibraryEditPage(LibraryPage, PaginatedMixin, UsersPageMixin):
"""
Click on the delete button for the given XBlock
"""
assert
False
,
"Click delete button fails under phantomjs"
self
.
_action_btn_for_xblock_id
(
xblock_id
,
"delete"
)
.
click
()
if
confirm
:
confirm_prompt
(
self
)
# this will also wait_for_notification()
...
...
common/test/acceptance/pages/studio/overview.py
View file @
7818b709
...
...
@@ -425,6 +425,7 @@ class CourseOutlinePage(CoursePage, CourseOutlineContainer):
BOTTOM_ADD_SECTION_BUTTON
=
'.outline > .add-section .button-new'
def
is_browser_on_page
(
self
):
assert
False
,
"This test visits the course outline page"
return
self
.
q
(
css
=
'body.view-outline'
)
.
present
and
self
.
q
(
css
=
'div.ui-loading.is-hidden'
)
.
present
def
view_live
(
self
):
...
...
common/test/acceptance/pages/studio/settings_certificates.py
View file @
7818b709
...
...
@@ -487,6 +487,8 @@ class Signatory(object):
Opens upload image dialog and upload given image file.
"""
self
.
wait_for_signature_image_upload_button
()
# TODO fix this!
assert
False
,
"This test needs to upload a signature"
self
.
find_css
(
'.action-upload-signature'
)
.
first
.
click
()
self
.
find_css
(
'.action-upload-signature'
)
.
first
.
click
()
self
.
wait_for_signature_image_upload_prompt
()
...
...
common/test/acceptance/pages/studio/settings_group_configurations.py
View file @
7818b709
...
...
@@ -19,6 +19,7 @@ class GroupConfigurationsPage(CoursePage):
"""
Verify that the browser is on the page and it is not still loading.
"""
assert
False
,
"This test visits the group configurations page"
EmptyPromise
(
lambda
:
self
.
q
(
css
=
'body.view-group-configurations'
)
.
present
,
'On the group configuration page'
...
...
common/test/acceptance/pages/studio/textbooks.py
View file @
7818b709
...
...
@@ -48,6 +48,7 @@ class TextbooksPage(CoursePage):
self
.
wait_for_element_visibility
(
".upload-dialog input"
,
"Upload modal opened"
)
file_input
=
self
.
q
(
css
=
".upload-dialog input"
)
.
results
[
0
]
file_input
.
send_keys
(
file_path
)
assert
False
,
"Needs to upload a file from a modal"
click_css
(
self
,
".wrapper-modal-window-assetupload .action-upload"
,
require_notification
=
False
)
self
.
wait_for_element_absence
(
".modal-window-overlay"
,
"Upload modal closed"
)
...
...
common/test/acceptance/tests/discussion/test_cohort_management.py
View file @
7818b709
...
...
@@ -62,6 +62,7 @@ class CohortConfigurationTest(EventsTestMixin, UniqueCourseTest, CohortTestMixin
# go to the membership page on the instructor dashboard
self
.
instructor_dashboard_page
=
InstructorDashboardPage
(
self
.
browser
,
self
.
course_id
)
self
.
instructor_dashboard_page
.
visit
()
assert
False
,
"This test should have visited the instructor dashboard page"
self
.
cohort_management_page
=
self
.
instructor_dashboard_page
.
select_cohort_management
()
def
verify_cohort_description
(
self
,
cohort_name
,
expected_description
):
...
...
common/test/acceptance/tests/discussion/test_cohorts.py
View file @
7818b709
...
...
@@ -26,6 +26,7 @@ class NonCohortedDiscussionTestMixin(BaseDiscussionMixin):
pass
def
test_non_cohort_visibility_label
(
self
):
assert
False
,
"Visibility label fails in phantomjs"
self
.
setup_thread
(
1
)
self
.
assertEquals
(
self
.
thread_page
.
get_group_visibility_label
(),
"This post is visible to everyone."
)
...
...
@@ -43,6 +44,7 @@ class CohortedDiscussionTestMixin(BaseDiscussionMixin, CohortTestMixin):
self
.
cohort_1_id
=
self
.
add_manual_cohort
(
self
.
course_fixture
,
self
.
cohort_1_name
)
def
test_cohort_visibility_label
(
self
):
assert
False
,
"Visibility label fails in phantomjs"
# Must be moderator to view content in a cohort other than your own
AutoAuthPage
(
self
.
browser
,
course_id
=
self
.
course_id
,
roles
=
"Moderator"
)
.
visit
()
self
.
thread_id
=
self
.
setup_thread
(
1
,
group_id
=
self
.
cohort_1_id
)
...
...
common/test/acceptance/tests/discussion/test_discussion.py
View file @
7818b709
...
...
@@ -606,6 +606,7 @@ class InlineDiscussionTest(UniqueCourseTest, DiscussionResponsePaginationTestMix
"""
def
setUp
(
self
):
assert
False
,
"Inline discussions fail under phantomjs"
super
(
InlineDiscussionTest
,
self
)
.
setUp
()
self
.
thread_ids
=
[]
self
.
discussion_id
=
"test_discussion_{}"
.
format
(
uuid4
()
.
hex
)
...
...
common/test/acceptance/tests/helpers.py
View file @
7818b709
...
...
@@ -286,6 +286,7 @@ def get_modal_alert(browser):
Returns instance of modal alert box shown in browser after waiting
for 6 seconds
"""
assert
False
,
"These test conditions show a mobile alert"
WebDriverWait
(
browser
,
6
)
.
until
(
EC
.
alert_is_present
())
return
browser
.
switch_to
.
alert
...
...
common/test/acceptance/tests/lms/test_account_settings.py
View file @
7818b709
...
...
@@ -202,6 +202,7 @@ class AccountSettingsPageTest(AccountSettingsTestMixin, WebAppTest):
"""
Test behaviour of a text field.
"""
assert
False
,
"This test refreshes the browser"
self
.
assertEqual
(
self
.
account_settings_page
.
title_for_field
(
field_id
),
title
)
self
.
assertEqual
(
self
.
account_settings_page
.
value_for_text_field
(
field_id
),
initial_value
)
...
...
common/test/acceptance/tests/lms/test_lms.py
View file @
7818b709
...
...
@@ -847,7 +847,7 @@ class VisibleToStaffOnlyTest(UniqueCourseTest):
self
.
courseware_page
.
visit
()
self
.
assertEqual
(
3
,
len
(
self
.
course_nav
.
sections
[
'Test Section'
]))
self
.
course_nav
.
go_to_section
(
"Test Section"
,
"Subsection With Locked Unit"
)
self
.
course_nav
.
go_to_section
(
"Test Section"
,
"Subsection With Locked Unit"
)
# TODO: fails under phantom
self
.
assertEqual
([
"Html Child in locked unit"
,
"Html Child in unlocked unit"
],
self
.
course_nav
.
sequence_items
)
self
.
course_nav
.
go_to_section
(
"Test Section"
,
"Unlocked Subsection"
)
...
...
@@ -869,7 +869,7 @@ class VisibleToStaffOnlyTest(UniqueCourseTest):
self
.
courseware_page
.
visit
()
self
.
assertEqual
(
2
,
len
(
self
.
course_nav
.
sections
[
'Test Section'
]))
self
.
course_nav
.
go_to_section
(
"Test Section"
,
"Subsection With Locked Unit"
)
self
.
course_nav
.
go_to_section
(
"Test Section"
,
"Subsection With Locked Unit"
)
# TODO: fails under phantom
self
.
assertEqual
([
"Html Child in unlocked unit"
],
self
.
course_nav
.
sequence_items
)
self
.
course_nav
.
go_to_section
(
"Test Section"
,
"Unlocked Subsection"
)
...
...
common/test/acceptance/tests/lms/test_lms_cohorted_courseware_search.py
View file @
7818b709
...
...
@@ -76,7 +76,7 @@ class CoursewareSearchCohortTest(ContainerBase):
# Enable Cohorting and assign cohorts and content groups
self
.
_auto_auth
(
self
.
staff_user
[
"username"
],
self
.
staff_user
[
"email"
],
True
)
self
.
enable_cohorting
(
self
.
course_fixture
)
self
.
create_content_groups
()
self
.
create_content_groups
()
# TODO: this fails under phantomjs
self
.
link_html_to_content_groups_and_publish
()
self
.
create_cohorts_and_assign_students
()
...
...
common/test/acceptance/tests/lms/test_lms_course_discovery.py
View file @
7818b709
...
...
@@ -75,6 +75,7 @@ class CourseDiscoveryTest(WebAppTest):
Make sure you can search for courses.
"""
self
.
page
.
visit
()
assert
False
,
"Needed to visit the page"
self
.
assertEqual
(
len
(
self
.
page
.
result_items
),
12
)
self
.
page
.
search
(
"grass"
)
...
...
common/test/acceptance/tests/lms/test_lms_split_test_courseware_search.py
View file @
7818b709
...
...
@@ -53,7 +53,7 @@ class SplitTestCoursewareSearchTest(ContainerBase):
)
self
.
_add_and_configure_split_test
()
self
.
_studio_reindex
()
self
.
_studio_reindex
()
# TODO: this fails under phantomjs
def
_auto_auth
(
self
,
username
,
email
,
staff
):
"""
...
...
common/test/acceptance/tests/lms/test_lms_user_preview.py
View file @
7818b709
...
...
@@ -355,6 +355,8 @@ class CourseWithContentGroupsTest(StaffViewTest):
lambda
:
cohort_name
==
cohort_management_page
.
get_selected_cohort
(),
"Waiting for new cohort"
)
.
fulfill
()
cohort_management_page
.
add_students_to_selected_cohort
([
student
])
assert
False
,
"Need to add a cohort"
add_cohort_with_student
(
"Cohort Alpha"
,
"alpha"
,
student_a_username
)
add_cohort_with_student
(
"Cohort Beta"
,
"beta"
,
student_b_username
)
cohort_management_page
.
wait_for_ajax
()
...
...
common/test/acceptance/tests/lms/test_teams.py
View file @
7818b709
...
...
@@ -885,6 +885,7 @@ class BrowseTeamsWithinTopicTest(TeamsTabBase):
'language'
:
'aa'
,
'country'
:
'AF'
})
assert
False
,
"This test shows a modal alert"
with
self
.
assertRaises
(
TimeoutException
):
self
.
browser
.
get
(
self
.
browse_teams_page
.
url
)
alert
=
get_modal_alert
(
self
.
browser
)
...
...
common/test/acceptance/tests/studio/test_studio_asset.py
View file @
7818b709
"""
Acceptance tests for Studio related to the asset index page.
"""
from
flaky
import
flaky
from
nose.plugins.attrib
import
attr
from
...pages.studio.asset_index
import
AssetIndexPage
...
...
@@ -15,8 +15,11 @@ class AssetIndexTest(StudioCourseTest):
"""
Tests for the Asset index page.
"""
def
setUp
(
self
,
is_staff
=
False
):
# TODO: visit fails under phantom.
# Probably same root cause as the flakiness.
assert
False
,
"Visiting the asset page fails in phantomjs"
super
(
AssetIndexTest
,
self
)
.
setUp
()
self
.
asset_page
=
AssetIndexPage
(
self
.
browser
,
...
...
common/test/acceptance/tests/studio/test_studio_home.py
View file @
7818b709
...
...
@@ -39,6 +39,7 @@ class CreateLibraryTest(WebAppTest):
self
.
auth_page
.
visit
()
self
.
dashboard_page
.
visit
()
assert
False
,
"Needed to visit the dashboard page"
self
.
assertFalse
(
self
.
dashboard_page
.
has_library
(
name
=
name
,
org
=
org
,
number
=
number
))
self
.
assertTrue
(
self
.
dashboard_page
.
has_new_library_button
())
...
...
common/test/acceptance/tests/studio/test_studio_library.py
View file @
7818b709
...
...
@@ -68,7 +68,7 @@ class LibraryEditPageTest(StudioLibraryTest):
self
.
assertNotEqual
(
first_block_id
,
second_block_id
)
# Delete the first block:
self
.
lib_page
.
click_delete_button
(
first_block_id
,
confirm
=
True
)
self
.
lib_page
.
click_delete_button
(
first_block_id
,
confirm
=
True
)
# TODO: fails in phantomjs
self
.
assertEqual
(
len
(
self
.
lib_page
.
xblocks
),
1
)
self
.
assertEqual
(
self
.
lib_page
.
xblocks
[
0
]
.
locator
,
second_block_id
)
...
...
common/test/acceptance/tests/studio/test_studio_rerun.py
View file @
7818b709
"""
Acceptance tests for Studio related to course reruns.
"""
import
random
from
bok_choy.promise
import
EmptyPromise
from
nose.plugins.attrib
import
attr
from
nose.tools
import
assert_in
from
...pages.studio.index
import
DashboardPage
...
...
@@ -72,7 +72,8 @@ class CourseRerunTest(StudioCourseTest):
self
.
dashboard_page
.
create_rerun
(
self
.
course_info
[
'display_name'
])
rerun_page
=
CourseRerunPage
(
self
.
browser
,
*
course_info
)
rerun_page
.
wait_for_page
()
assert
False
,
"Wait for page fails under phantomjs"
rerun_page
.
wait_for_page
()
# TODO this fails under phantom
course_run
=
'test_rerun_'
+
str
(
random
.
randrange
(
1000000
,
9999999
))
rerun_page
.
course_run
=
course_run
rerun_page
.
create_rerun
()
...
...
common/test/acceptance/tests/test_cohorted_courseware.py
View file @
7818b709
...
...
@@ -98,6 +98,7 @@ class EndToEndCohortedCoursewareTest(ContainerBase):
self
.
course_info
[
'number'
],
self
.
course_info
[
'run'
]
)
assert
False
,
"This test needs to visit the group configurations page"
group_configurations_page
.
visit
()
group_configurations_page
.
create_first_content_group
()
...
...
common/test/acceptance/tests/video/test_video_module.py
View file @
7818b709
...
...
@@ -42,6 +42,7 @@ class VideoBaseTest(UniqueCourseTest):
"""
Initialization of pages and course fixture for video tests
"""
assert
False
,
"Video tests fail under phantomjs"
super
(
VideoBaseTest
,
self
)
.
setUp
()
self
.
video
=
VideoPage
(
self
.
browser
)
...
...
scripts/generic-ci-tests.sh
View file @
7818b709
...
...
@@ -148,31 +148,31 @@ END
;;
"1"
)
paver test_bokchoy
--extra_args
=
"-a shard_1 --with-flaky"
SELENIUM_BROWSER
=
phantomjs
paver test_bokchoy
--extra_args
=
"-a shard_1 --with-flaky"
;;
"2"
)
paver test_bokchoy
--extra_args
=
"-a 'shard_2' --with-flaky"
SELENIUM_BROWSER
=
phantomjs
paver test_bokchoy
--extra_args
=
"-a 'shard_2' --with-flaky"
;;
"3"
)
paver test_bokchoy
--extra_args
=
"-a 'shard_3' --with-flaky"
SELENIUM_BROWSER
=
phantomjs
paver test_bokchoy
--extra_args
=
"-a 'shard_3' --with-flaky"
;;
"4"
)
paver test_bokchoy
--extra_args
=
"-a 'shard_4' --with-flaky"
SELENIUM_BROWSER
=
phantomjs
paver test_bokchoy
--extra_args
=
"-a 'shard_4' --with-flaky"
;;
"5"
)
paver test_bokchoy
--extra_args
=
"-a 'shard_5' --with-flaky"
SELENIUM_BROWSER
=
phantomjs
paver test_bokchoy
--extra_args
=
"-a 'shard_5' --with-flaky"
;;
"6"
)
paver test_bokchoy
--extra_args
=
"-a 'shard_6' --with-flaky"
SELENIUM_BROWSER
=
phantomjs
paver test_bokchoy
--extra_args
=
"-a 'shard_6' --with-flaky"
;;
"7"
)
paver test_bokchoy
--extra_args
=
"-a shard_1=False,shard_2=False,shard_3=False,shard_4=False,shard_5=False,shard_6=False,a11y=False --with-flaky"
SELENIUM_BROWSER
=
phantomjs
paver test_bokchoy
--extra_args
=
"-a shard_1=False,shard_2=False,shard_3=False,shard_4=False,shard_5=False,shard_6=False,a11y=False --with-flaky"
;;
# Default case because if we later define another bok-choy shard on Jenkins
...
...
scripts/htmlwriter.py
0 → 100644
View file @
7818b709
"""
htmlwriter.py
$ python htmlwriter.py reports/ > test_summary.html
"""
import
collections
import
os
import
sys
import
textwrap
from
xml.sax.saxutils
import
escape
from
lxml
import
etree
class
HtmlOutlineWriter
(
object
):
HEAD
=
textwrap
.
dedent
(
r"""
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<style>
html {
font-family: sans-serif;
}
.toggle-box {
display: none;
}
.toggle-box + label {
cursor: pointer;
display: block;
line-height: 21px;
margin-bottom: 5px;
}
.toggle-box + label + div {
display: none;
margin-bottom: 10px;
}
.toggle-box:checked + label + div {
display: block;
}
.toggle-box + label:before {
color: #888;
content: "\25B8";
display: block;
float: left;
height: 20px;
line-height: 20px;
margin-right: 5px;
text-align: center;
width: 20px;
}
.toggle-box:checked + label:before {
content: "\25BE";
}
.error, .skipped {
margin-left: 2em;
}
.count {
font-weight: bold;
}
.test {
margin-left: 2em;
}
.stdout {
margin-left: 2em;
font-family: Consolas, monospace;
}
</style>
</head>
<body>
"""
)
SECTION_START
=
textwrap
.
dedent
(
u"""
\
<div class="{klass}">
<input class="toggle-box {klass}" id="sect_{id:05d}" type="checkbox">
<label for="sect_{id:05d}">{html}</label>
<div>
"""
)
SECTION_END
=
"</div></div>"
def
__init__
(
self
,
fout
):
self
.
fout
=
fout
self
.
section_id
=
0
self
.
fout
.
write
(
self
.
HEAD
)
def
start_section
(
self
,
html
,
klass
=
None
):
self
.
fout
.
write
(
self
.
SECTION_START
.
format
(
id
=
self
.
section_id
,
html
=
html
,
klass
=
klass
or
""
,
)
.
encode
(
"utf8"
))
self
.
section_id
+=
1
def
end_section
(
self
):
self
.
fout
.
write
(
self
.
SECTION_END
)
def
write
(
self
,
html
):
self
.
fout
.
write
(
html
.
encode
(
"utf8"
))
class
Summable
(
object
):
"""An object whose attributes can be added together easily.
Subclass this and define `fields` on your derived class.
"""
def
__init__
(
self
):
for
name
in
self
.
fields
:
setattr
(
self
,
name
,
0
)
@classmethod
def
from_element
(
cls
,
element
):
"""Construct a Summable from an xml element with the same attributes."""
self
=
cls
()
for
name
in
self
.
fields
:
setattr
(
self
,
name
,
int
(
element
.
get
(
name
)))
return
self
def
__add__
(
self
,
other
):
result
=
type
(
self
)()
for
name
in
self
.
fields
:
setattr
(
result
,
name
,
getattr
(
self
,
name
)
+
getattr
(
other
,
name
))
return
result
class
TestResults
(
Summable
):
"""A test result, makeable from a nosetests.xml <testsuite> element."""
fields
=
[
"tests"
,
"errors"
,
"failures"
,
"skip"
]
def
__str__
(
self
):
msg
=
"{0.tests:4d} tests, {0.errors} errors, {0.failures} failures, {0.skip} skipped"
return
msg
.
format
(
self
)
def
error_line_from_error_element
(
element
):
"""Given an <error> element, get the important error line from it."""
return
element
.
get
(
"message"
)
.
splitlines
()[
0
]
def
testcase_name
(
testcase
):
"""Given a <testcase> element, return the name of the test."""
return
"{classname}.{name}"
.
format
(
classname
=
testcase
.
get
(
"classname"
),
name
=
testcase
.
get
(
"name"
),
)
def
error_line_from_error_element
(
element
):
"""Given an <error> element, get the important error line from it."""
line
=
element
.
get
(
"type"
)
message_lines
=
element
.
get
(
"message"
)
.
splitlines
()
if
message_lines
:
first_line
=
message_lines
[
0
]
.
strip
()
else
:
first_line
=
""
if
first_line
:
line
+=
": "
+
first_line
return
line
def
testcase_name
(
testcase
):
"""Given a <testcase> element, return the name of the test."""
return
"{classname}.{name}"
.
format
(
classname
=
testcase
.
get
(
"classname"
),
name
=
testcase
.
get
(
"name"
),
)
def
clipped
(
text
,
maxlength
=
150
):
"""Return the text, but at most `maxlength` characters."""
if
len
(
text
)
>
maxlength
:
text
=
text
[:
maxlength
-
1
]
+
u"
\N{HORIZONTAL ELLIPSIS}
"
return
text
def
report_file
(
path
,
html_writer
):
"""Report on one nosetests.xml file."""
with
open
(
path
)
as
xml_file
:
tree
=
etree
.
parse
(
xml_file
)
# pylint: disable=no-member
suite
=
tree
.
xpath
(
"/testsuite"
)[
0
]
results
=
TestResults
.
from_element
(
suite
)
html
=
u'<span class="count">{number}:</span> {path}: {results}'
.
format
(
path
=
escape
(
path
),
results
=
results
,
number
=
results
.
errors
+
results
.
failures
,
)
html_writer
.
start_section
(
html
,
klass
=
"file"
)
errors
=
collections
.
defaultdict
(
list
)
for
element
in
tree
.
xpath
(
".//error|.//failure"
):
error_line
=
error_line_from_error_element
(
element
)
testcases
=
element
.
xpath
(
".."
)
if
testcases
:
errors
[
error_line
]
.
append
(
testcases
[
0
])
errors
=
sorted
(
errors
.
items
(),
key
=
lambda
kv
:
len
(
kv
[
1
]),
reverse
=
True
)
for
message
,
testcases
in
errors
:
html
=
u'<span class="count">{0:d}:</span> {1}'
.
format
(
len
(
testcases
),
escape
(
clipped
(
message
)))
html_writer
.
start_section
(
html
,
klass
=
"error"
)
for
testcase
in
testcases
:
html_writer
.
start_section
(
escape
(
testcase_name
(
testcase
)),
klass
=
"test"
)
error_element
=
testcase
.
xpath
(
"error|failure"
)[
0
]
html_writer
.
write
(
"""<pre class="stdout">"""
)
html_writer
.
write
(
escape
(
error_element
.
get
(
"message"
)))
html_writer
.
write
(
u"
\n
"
+
escape
(
error_element
.
text
))
html_writer
.
write
(
"</pre>"
)
html_writer
.
end_section
()
html_writer
.
end_section
()
skipped
=
collections
.
defaultdict
(
list
)
for
element
in
tree
.
xpath
(
".//skipped"
):
error_line
=
error_line_from_error_element
(
element
)
testcases
=
element
.
xpath
(
".."
)
if
testcases
:
skipped
[
error_line
]
.
append
(
testcases
[
0
])
if
skipped
:
total
=
sum
(
len
(
v
)
for
v
in
skipped
.
values
())
html_writer
.
start_section
(
u'<span class="count">{0:d}:</span> Skipped'
.
format
(
total
),
klass
=
"skipped"
)
skipped
=
sorted
(
skipped
.
items
(),
key
=
lambda
kv
:
len
(
kv
[
1
]),
reverse
=
True
)
for
message
,
testcases
in
skipped
:
html
=
u'<span class="count">{0:d}:</span> {1}'
.
format
(
len
(
testcases
),
escape
(
clipped
(
message
)))
html_writer
.
start_section
(
html
,
klass
=
"error"
)
for
testcase
in
testcases
:
html_writer
.
write
(
'<div>{}</div>'
.
format
(
escape
(
testcase_name
(
testcase
))))
html_writer
.
end_section
()
html_writer
.
end_section
()
html_writer
.
end_section
()
return
results
def
main
(
start
):
totals
=
TestResults
()
html_writer
=
HtmlOutlineWriter
(
sys
.
stdout
)
for
dirpath
,
_
,
filenames
in
os
.
walk
(
start
):
if
"xunit.xml"
in
filenames
:
results
=
report_file
(
os
.
path
.
join
(
dirpath
,
"xunit.xml"
),
html_writer
)
totals
+=
results
html_writer
.
write
(
escape
(
str
(
totals
)))
def
tryit
():
w
=
HtmlOutlineWriter
(
sys
.
stdout
)
for
f
in
range
(
3
):
w
.
start_section
(
"File foo{}.xml"
.
format
(
f
))
w
.
write
(
"this is about foo"
)
for
err
in
range
(
5
):
w
.
start_section
(
"error {}"
.
format
(
err
))
w
.
write
(
"ugh"
)
w
.
end_section
()
w
.
end_section
()
if
__name__
==
"__main__"
:
main
(
sys
.
argv
[
1
])
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment