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
182e34f8
Commit
182e34f8
authored
Apr 07, 2016
by
Renzo Lucioni
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Acceptance tests for program listing page
Includes a11y coverage. ECOM-3980.
parent
5bb0e908
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
212 additions
and
39 deletions
+212
-39
common/test/acceptance/fixtures/__init__.py
+1
-1
common/test/acceptance/fixtures/config.py
+4
-4
common/test/acceptance/fixtures/programs.py
+70
-12
common/test/acceptance/pages/lms/programs.py
+22
-0
common/test/acceptance/tests/lms/test_programs.py
+102
-0
common/test/acceptance/tests/studio/test_studio_home.py
+13
-22
No files found.
common/test/acceptance/fixtures/__init__.py
View file @
182e34f8
...
@@ -18,5 +18,5 @@ COMMENTS_STUB_URL = os.environ.get('comments_url', 'http://localhost:4567')
...
@@ -18,5 +18,5 @@ COMMENTS_STUB_URL = os.environ.get('comments_url', 'http://localhost:4567')
# Get the URL of the EdxNotes service stub used in the test
# Get the URL of the EdxNotes service stub used in the test
EDXNOTES_STUB_URL
=
os
.
environ
.
get
(
'edxnotes_url'
,
'http://localhost:8042'
)
EDXNOTES_STUB_URL
=
os
.
environ
.
get
(
'edxnotes_url'
,
'http://localhost:8042'
)
# Get the URL of the
EdxNote
s service stub used in the test
# Get the URL of the
Program
s service stub used in the test
PROGRAMS_STUB_URL
=
os
.
environ
.
get
(
'programs_url'
,
'http://localhost:8090'
)
PROGRAMS_STUB_URL
=
os
.
environ
.
get
(
'programs_url'
,
'http://localhost:8090'
)
common/test/acceptance/fixtures/config.py
View file @
182e34f8
...
@@ -9,7 +9,7 @@ from lazy import lazy
...
@@ -9,7 +9,7 @@ from lazy import lazy
from
.
import
LMS_BASE_URL
from
.
import
LMS_BASE_URL
class
ConfigModelFixureError
(
Exception
):
class
ConfigModelFix
t
ureError
(
Exception
):
"""
"""
Error occurred while configuring the stub XQueue.
Error occurred while configuring the stub XQueue.
"""
"""
...
@@ -41,7 +41,7 @@ class ConfigModelFixture(object):
...
@@ -41,7 +41,7 @@ class ConfigModelFixture(object):
)
)
if
not
response
.
ok
:
if
not
response
.
ok
:
raise
ConfigModelFixureError
(
raise
ConfigModelFix
t
ureError
(
"Could not configure url '{}'. response: {} - {}"
.
format
(
"Could not configure url '{}'. response: {} - {}"
.
format
(
self
.
_api_base
,
self
.
_api_base
,
response
,
response
,
...
@@ -53,7 +53,7 @@ class ConfigModelFixture(object):
...
@@ -53,7 +53,7 @@ class ConfigModelFixture(object):
def
session_cookies
(
self
):
def
session_cookies
(
self
):
"""
"""
Log in as a staff user, then return the cookies for the session (as a dict)
Log in as a staff user, then return the cookies for the session (as a dict)
Raises a `ConfigModelFixureError` if the login fails.
Raises a `ConfigModelFix
t
ureError` if the login fails.
"""
"""
return
{
key
:
val
for
key
,
val
in
self
.
session
.
cookies
.
items
()}
return
{
key
:
val
for
key
,
val
in
self
.
session
.
cookies
.
items
()}
...
@@ -92,4 +92,4 @@ class ConfigModelFixture(object):
...
@@ -92,4 +92,4 @@ class ConfigModelFixture(object):
else
:
else
:
msg
=
"Could not log in to use ConfigModel restful API. Status code: {0}"
.
format
(
response
.
status_code
)
msg
=
"Could not log in to use ConfigModel restful API. Status code: {0}"
.
format
(
response
.
status_code
)
raise
ConfigModelFixureError
(
msg
)
raise
ConfigModelFix
t
ureError
(
msg
)
common/test/acceptance/fixtures/programs.py
View file @
182e34f8
"""
"""
Tools to create programs-related data for use in bok choy tests.
Tools to create programs-related data for use in bok choy tests.
"""
"""
from
collections
import
namedtuple
import
json
import
json
import
factory
import
factory
import
requests
import
requests
from
.
import
PROGRAMS_STUB_URL
from
.
import
PROGRAMS_STUB_URL
from
.config
import
ConfigModelFixture
FakeProgram
=
namedtuple
(
'FakeProgram'
,
[
'name'
,
'status'
,
'org_key'
,
'course_id'
])
class
Program
(
factory
.
Factory
):
class
Program
(
factory
.
Factory
):
...
@@ -17,12 +22,14 @@ class Program(factory.Factory):
...
@@ -17,12 +22,14 @@ class Program(factory.Factory):
model
=
dict
model
=
dict
id
=
factory
.
Sequence
(
lambda
n
:
n
)
# pylint: disable=invalid-name
id
=
factory
.
Sequence
(
lambda
n
:
n
)
# pylint: disable=invalid-name
name
=
"dummy-program-name"
name
=
'dummy-program-name'
subtitle
=
"dummy-program-subtitle"
subtitle
=
'dummy-program-subtitle'
category
=
"xseries"
category
=
'xseries'
status
=
"unpublished"
status
=
'unpublished'
marketing_slug
=
factory
.
Sequence
(
lambda
n
:
'slug-{}'
.
format
(
n
))
# pylint: disable=unnecessary-lambda
organizations
=
[]
organizations
=
[]
course_codes
=
[]
course_codes
=
[]
banner_image_urls
=
{}
class
Organization
(
factory
.
Factory
):
class
Organization
(
factory
.
Factory
):
...
@@ -32,8 +39,30 @@ class Organization(factory.Factory):
...
@@ -32,8 +39,30 @@ class Organization(factory.Factory):
class
Meta
(
object
):
class
Meta
(
object
):
model
=
dict
model
=
dict
key
=
"dummyX"
key
=
'dummyX'
display_name
=
"dummy-org-display-name"
display_name
=
'dummy-org-display-name'
class
CourseCode
(
factory
.
Factory
):
"""
Factory for stubbing nested course code resources from the Programs API (v1).
"""
class
Meta
(
object
):
model
=
dict
display_name
=
'dummy-org-display-name'
run_modes
=
[]
class
RunMode
(
factory
.
Factory
):
"""
Factory for stubbing nested run mode resources from the Programs API (v1).
"""
class
Meta
(
object
):
model
=
dict
course_key
=
'org/course/run'
mode_slug
=
'verified'
class
ProgramsFixture
(
object
):
class
ProgramsFixture
(
object
):
...
@@ -41,16 +70,24 @@ class ProgramsFixture(object):
...
@@ -41,16 +70,24 @@ class ProgramsFixture(object):
Interface to set up mock responses from the Programs stub server.
Interface to set up mock responses from the Programs stub server.
"""
"""
def
install_programs
(
self
,
program_value
s
):
def
install_programs
(
self
,
fake_program
s
):
"""
"""
Sets the response data for the programs list endpoint.
Sets the response data for the programs list endpoint.
At present, `
program_values` needs to be a sequence of sequences of (program_name, org_key)
.
At present, `
fake_programs` must be a iterable of FakeProgram named tuples
.
"""
"""
programs
=
[]
programs
=
[]
for
program_name
,
org_key
in
program_values
:
for
program
in
fake_programs
:
org
=
Organization
(
key
=
org_key
)
run_mode
=
RunMode
(
course_key
=
program
.
course_id
)
program
=
Program
(
name
=
program_name
,
organizations
=
[
org
])
course_code
=
CourseCode
(
run_modes
=
[
run_mode
])
org
=
Organization
(
key
=
program
.
org_key
)
program
=
Program
(
name
=
program
.
name
,
status
=
program
.
status
,
organizations
=
[
org
],
course_codes
=
[
course_code
]
)
programs
.
append
(
program
)
programs
.
append
(
program
)
api_result
=
{
'results'
:
programs
}
api_result
=
{
'results'
:
programs
}
...
@@ -59,3 +96,24 @@ class ProgramsFixture(object):
...
@@ -59,3 +96,24 @@ class ProgramsFixture(object):
'{}/set_config'
.
format
(
PROGRAMS_STUB_URL
),
'{}/set_config'
.
format
(
PROGRAMS_STUB_URL
),
data
=
{
'programs'
:
json
.
dumps
(
api_result
)},
data
=
{
'programs'
:
json
.
dumps
(
api_result
)},
)
)
class
ProgramsConfigMixin
(
object
):
"""Mixin providing a method used to configure the programs feature."""
def
set_programs_api_configuration
(
self
,
is_enabled
=
False
,
api_version
=
1
,
api_url
=
PROGRAMS_STUB_URL
,
js_path
=
'/js'
,
css_path
=
'/css'
):
"""Dynamically adjusts the Programs config model during tests."""
ConfigModelFixture
(
'/config/programs'
,
{
'enabled'
:
is_enabled
,
'api_version_number'
:
api_version
,
'internal_service_url'
:
api_url
,
'public_service_url'
:
api_url
,
'authoring_app_js_path'
:
js_path
,
'authoring_app_css_path'
:
css_path
,
'cache_ttl'
:
0
,
'enable_student_dashboard'
:
is_enabled
,
'enable_studio_tab'
:
is_enabled
,
'enable_certification'
:
is_enabled
,
'xseries_ad_enabled'
:
is_enabled
,
'program_listing_enabled'
:
is_enabled
,
})
.
install
()
common/test/acceptance/pages/lms/programs.py
0 → 100644
View file @
182e34f8
"""LMS-hosted Programs pages"""
from
bok_choy.page_object
import
PageObject
from
.
import
BASE_URL
class
ProgramListingPage
(
PageObject
):
"""Program listing page."""
url
=
BASE_URL
+
'/dashboard/programs/'
def
is_browser_on_page
(
self
):
return
self
.
q
(
css
=
'.program-list-wrapper'
)
.
present
@property
def
are_cards_present
(
self
):
"""Check whether program cards are present."""
return
self
.
q
(
css
=
'.program-card'
)
.
present
@property
def
is_sidebar_present
(
self
):
"""Check whether sidebar is present."""
return
self
.
q
(
css
=
'.sidebar'
)
.
present
common/test/acceptance/tests/lms/test_programs.py
0 → 100644
View file @
182e34f8
"""Acceptance tests for LMS-hosted Programs pages"""
from
nose.plugins.attrib
import
attr
from
...fixtures.programs
import
FakeProgram
,
ProgramsFixture
,
ProgramsConfigMixin
from
...fixtures.course
import
CourseFixture
from
..helpers
import
UniqueCourseTest
from
...pages.lms.auto_auth
import
AutoAuthPage
from
...pages.lms.programs
import
ProgramListingPage
class
ProgramListingPageBase
(
ProgramsConfigMixin
,
UniqueCourseTest
):
"""Base class used for program listing page tests."""
def
setUp
(
self
):
super
(
ProgramListingPageBase
,
self
)
.
setUp
()
self
.
set_programs_api_configuration
(
is_enabled
=
True
)
self
.
listing_page
=
ProgramListingPage
(
self
.
browser
)
def
stub_api
(
self
,
course_id
=
None
):
"""Stub out the programs API with fake data."""
name
=
'Fake Program'
status
=
'active'
org_key
=
self
.
course_info
[
'org'
]
course_id
=
course_id
if
course_id
else
self
.
course_id
ProgramsFixture
()
.
install_programs
([
FakeProgram
(
name
=
name
,
status
=
status
,
org_key
=
org_key
,
course_id
=
course_id
),
])
def
auth
(
self
,
enroll
=
True
):
"""Authenticate, enrolling the user in the configured course if requested."""
CourseFixture
(
**
self
.
course_info
)
.
install
()
course_id
=
self
.
course_id
if
enroll
else
None
AutoAuthPage
(
self
.
browser
,
course_id
=
course_id
)
.
visit
()
class
ProgramListingPageTest
(
ProgramListingPageBase
):
"""Verify user-facing behavior of the program listing page."""
def
test_no_enrollments
(
self
):
"""Verify that no cards appear when the user has no enrollments."""
self
.
stub_api
()
self
.
auth
(
enroll
=
False
)
self
.
listing_page
.
visit
()
self
.
assertTrue
(
self
.
listing_page
.
is_sidebar_present
)
self
.
assertFalse
(
self
.
listing_page
.
are_cards_present
)
def
test_no_programs
(
self
):
"""
Verify that no cards appear when the user has enrollments
but none are included in an active program.
"""
course_id
=
self
.
course_id
.
replace
(
self
.
course_info
[
'run'
],
'other_run'
)
self
.
stub_api
(
course_id
=
course_id
)
self
.
auth
()
self
.
listing_page
.
visit
()
self
.
assertTrue
(
self
.
listing_page
.
is_sidebar_present
)
self
.
assertFalse
(
self
.
listing_page
.
are_cards_present
)
def
test_enrollments_and_programs
(
self
):
"""
Verify that cards appear when the user has enrollments
which are included in at least one active program.
"""
self
.
stub_api
()
self
.
auth
()
self
.
listing_page
.
visit
()
self
.
assertTrue
(
self
.
listing_page
.
is_sidebar_present
)
self
.
assertTrue
(
self
.
listing_page
.
are_cards_present
)
@attr
(
'a11y'
)
class
ProgramListingPageA11yTest
(
ProgramListingPageBase
):
"""Test program listing page accessibility."""
def
test_empty_a11y
(
self
):
"""Test a11y of the page's empty state."""
self
.
stub_api
()
self
.
auth
(
enroll
=
False
)
self
.
listing_page
.
visit
()
self
.
assertTrue
(
self
.
listing_page
.
is_sidebar_present
)
self
.
assertFalse
(
self
.
listing_page
.
are_cards_present
)
self
.
listing_page
.
a11y_audit
.
check_for_accessibility_errors
()
def
test_cards_a11y
(
self
):
"""Test a11y when program cards are present."""
self
.
stub_api
()
self
.
auth
()
self
.
listing_page
.
visit
()
self
.
assertTrue
(
self
.
listing_page
.
is_sidebar_present
)
self
.
assertTrue
(
self
.
listing_page
.
are_cards_present
)
self
.
listing_page
.
a11y_audit
.
check_for_accessibility_errors
()
common/test/acceptance/tests/studio/test_studio_home.py
View file @
182e34f8
...
@@ -8,7 +8,7 @@ from uuid import uuid4
...
@@ -8,7 +8,7 @@ from uuid import uuid4
from
...fixtures
import
PROGRAMS_STUB_URL
from
...fixtures
import
PROGRAMS_STUB_URL
from
...fixtures.config
import
ConfigModelFixture
from
...fixtures.config
import
ConfigModelFixture
from
...fixtures.programs
import
ProgramsFixture
from
...fixtures.programs
import
FakeProgram
,
ProgramsFixture
,
ProgramsConfigMixin
from
...pages.studio.auto_auth
import
AutoAuthPage
from
...pages.studio.auto_auth
import
AutoAuthPage
from
...pages.studio.library
import
LibraryEditPage
from
...pages.studio.library
import
LibraryEditPage
from
...pages.studio.index
import
DashboardPage
,
DashboardPageWithPrograms
from
...pages.studio.index
import
DashboardPage
,
DashboardPageWithPrograms
...
@@ -69,7 +69,7 @@ class CreateLibraryTest(WebAppTest):
...
@@ -69,7 +69,7 @@ class CreateLibraryTest(WebAppTest):
self
.
assertTrue
(
self
.
dashboard_page
.
has_library
(
name
=
name
,
org
=
org
,
number
=
number
))
self
.
assertTrue
(
self
.
dashboard_page
.
has_library
(
name
=
name
,
org
=
org
,
number
=
number
))
class
DashboardProgramsTabTest
(
WebAppTest
):
class
DashboardProgramsTabTest
(
ProgramsConfigMixin
,
WebAppTest
):
"""
"""
Test the programs tab on the studio home page.
Test the programs tab on the studio home page.
"""
"""
...
@@ -81,23 +81,6 @@ class DashboardProgramsTabTest(WebAppTest):
...
@@ -81,23 +81,6 @@ class DashboardProgramsTabTest(WebAppTest):
self
.
dashboard_page
=
DashboardPageWithPrograms
(
self
.
browser
)
self
.
dashboard_page
=
DashboardPageWithPrograms
(
self
.
browser
)
self
.
auth_page
.
visit
()
self
.
auth_page
.
visit
()
def
set_programs_api_configuration
(
self
,
is_enabled
=
False
,
api_version
=
1
,
api_url
=
PROGRAMS_STUB_URL
,
js_path
=
'/js'
,
css_path
=
'/css'
):
"""
Dynamically adjusts the programs API config model during tests.
"""
ConfigModelFixture
(
'/config/programs'
,
{
'enabled'
:
is_enabled
,
'enable_studio_tab'
:
is_enabled
,
'enable_student_dashboard'
:
is_enabled
,
'api_version_number'
:
api_version
,
'internal_service_url'
:
api_url
,
'public_service_url'
:
api_url
,
'authoring_app_js_path'
:
js_path
,
'authoring_app_css_path'
:
css_path
,
'cache_ttl'
:
0
})
.
install
()
def
test_tab_is_disabled
(
self
):
def
test_tab_is_disabled
(
self
):
"""
"""
The programs tab and "new program" button should not appear at all
The programs tab and "new program" button should not appear at all
...
@@ -128,16 +111,24 @@ class DashboardProgramsTabTest(WebAppTest):
...
@@ -128,16 +111,24 @@ class DashboardProgramsTabTest(WebAppTest):
via config, and the results of the program list should display when
via config, and the results of the program list should display when
the list is nonempty.
the list is nonempty.
"""
"""
test_program_values
=
[(
'first program'
,
'org1'
),
(
'second program'
,
'org2'
)]
test_program_values
=
[
FakeProgram
(
name
=
'first program'
,
status
=
'unpublished'
,
org_key
=
'org1'
,
course_id
=
'foo/bar/baz'
),
FakeProgram
(
name
=
'second program'
,
status
=
'unpublished'
,
org_key
=
'org2'
,
course_id
=
'qux/quux/corge'
),
]
ProgramsFixture
()
.
install_programs
(
test_program_values
)
ProgramsFixture
()
.
install_programs
(
test_program_values
)
self
.
set_programs_api_configuration
(
True
)
self
.
set_programs_api_configuration
(
True
)
self
.
dashboard_page
.
visit
()
self
.
dashboard_page
.
visit
()
self
.
assertTrue
(
self
.
dashboard_page
.
is_programs_tab_present
())
self
.
assertTrue
(
self
.
dashboard_page
.
is_programs_tab_present
())
self
.
assertTrue
(
self
.
dashboard_page
.
is_new_program_button_present
())
self
.
assertTrue
(
self
.
dashboard_page
.
is_new_program_button_present
())
results
=
self
.
dashboard_page
.
get_program_list
()
self
.
assertEqual
(
results
,
test_program_values
)
self
.
assertFalse
(
self
.
dashboard_page
.
is_empty_list_create_button_present
())
self
.
assertFalse
(
self
.
dashboard_page
.
is_empty_list_create_button_present
())
results
=
self
.
dashboard_page
.
get_program_list
()
expected
=
[(
p
.
name
,
p
.
org_key
)
for
p
in
test_program_values
]
self
.
assertEqual
(
results
,
expected
)
def
test_tab_requires_staff
(
self
):
def
test_tab_requires_staff
(
self
):
"""
"""
The programs tab and "new program" button will not be available, even
The programs tab and "new program" button will not be available, even
...
...
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