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
d38e69c6
Commit
d38e69c6
authored
Dec 16, 2014
by
Braden MacDonald
Committed by
E. Kolpakov
Jan 12, 2015
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Acceptance & Jasmine tests for library permissions editor
parent
93bb1f58
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
561 additions
and
3 deletions
+561
-3
cms/static/coffee/spec/main.coffee
+1
-0
cms/static/js/spec/views/pages/library_users_spec.js
+78
-0
cms/templates/js/mock/mock-manage-users-lib.underscore
+146
-0
common/djangoapps/student/views.py
+5
-1
common/test/acceptance/pages/studio/auto_auth.py
+5
-2
common/test/acceptance/pages/studio/users.py
+189
-0
common/test/acceptance/tests/studio/test_studio_library.py
+137
-0
No files found.
cms/static/coffee/spec/main.coffee
View file @
d38e69c6
...
@@ -256,6 +256,7 @@ define([
...
@@ -256,6 +256,7 @@ define([
"js/spec/views/pages/course_outline_spec"
,
"js/spec/views/pages/course_outline_spec"
,
"js/spec/views/pages/course_rerun_spec"
,
"js/spec/views/pages/course_rerun_spec"
,
"js/spec/views/pages/index_spec"
,
"js/spec/views/pages/index_spec"
,
"js/spec/views/pages/library_users_spec"
,
"js/spec/views/modals/base_modal_spec"
,
"js/spec/views/modals/base_modal_spec"
,
"js/spec/views/modals/edit_xblock_spec"
,
"js/spec/views/modals/edit_xblock_spec"
,
...
...
cms/static/js/spec/views/pages/library_users_spec.js
0 → 100644
View file @
d38e69c6
define
([
"jquery"
,
"js/common_helpers/ajax_helpers"
,
"js/spec_helpers/view_helpers"
,
"js/factories/manage_users_lib"
,
"js/views/utils/view_utils"
],
function
(
$
,
AjaxHelpers
,
ViewHelpers
,
ManageUsersFactory
,
ViewUtils
)
{
"use strict"
;
describe
(
"Library Instructor Access Page"
,
function
()
{
var
mockHTML
=
readFixtures
(
'mock/mock-manage-users-lib.underscore'
);
beforeEach
(
function
()
{
ViewHelpers
.
installMockAnalytics
();
appendSetFixtures
(
mockHTML
);
ManageUsersFactory
(
"Mock Library"
,
[
"honor@example.com"
,
"audit@example.com"
,
"staff@example.com"
],
"dummy_change_role_url"
);
});
afterEach
(
function
()
{
ViewHelpers
.
removeMockAnalytics
();
});
it
(
"can give a user permission to use the library"
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
var
reloadSpy
=
spyOn
(
ViewUtils
,
'reload'
);
$
(
'.create-user-button'
).
click
();
expect
(
$
(
'.wrapper-create-user'
)).
toHaveClass
(
'is-shown'
);
$
(
'.user-email-input'
).
val
(
'other@example.com'
);
$
(
'.form-create.create-user .action-primary'
).
click
();
AjaxHelpers
.
expectJsonRequest
(
requests
,
'POST'
,
'dummy_change_role_url'
,
{
role
:
'library_user'
});
AjaxHelpers
.
respondWithJson
(
requests
,
{
'result'
:
'ok'
});
expect
(
reloadSpy
).
toHaveBeenCalled
();
});
it
(
"can cancel adding a user to the library"
,
function
()
{
$
(
'.create-user-button'
).
click
();
$
(
'.form-create.create-user .action-secondary'
).
click
();
expect
(
$
(
'.wrapper-create-user'
)).
not
.
toHaveClass
(
'is-shown'
);
});
it
(
"displays an error when the required field is blank"
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
$
(
'.create-user-button'
).
click
();
$
(
'.user-email-input'
).
val
(
''
);
var
errorPromptSelector
=
'.wrapper-prompt.is-shown .prompt.error'
;
expect
(
$
(
errorPromptSelector
).
length
).
toEqual
(
0
);
$
(
'.form-create.create-user .action-primary'
).
click
();
expect
(
$
(
errorPromptSelector
).
length
).
toEqual
(
1
);
expect
(
$
(
errorPromptSelector
)).
toContainText
(
'You must enter a valid email address'
);
expect
(
requests
.
length
).
toEqual
(
0
);
});
it
(
"displays an error when the user has already been added"
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
$
(
'.create-user-button'
).
click
();
$
(
'.user-email-input'
).
val
(
'honor@example.com'
);
var
warningPromptSelector
=
'.wrapper-prompt.is-shown .prompt.warning'
;
expect
(
$
(
warningPromptSelector
).
length
).
toEqual
(
0
);
$
(
'.form-create.create-user .action-primary'
).
click
();
expect
(
$
(
warningPromptSelector
).
length
).
toEqual
(
1
);
expect
(
$
(
warningPromptSelector
)).
toContainText
(
'Already a library team member'
);
expect
(
requests
.
length
).
toEqual
(
0
);
});
it
(
"can remove a user's permission to access the library"
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
var
reloadSpy
=
spyOn
(
ViewUtils
,
'reload'
);
$
(
'.user-item[data-email="honor@example.com"] .action-delete .delete'
).
click
();
expect
(
$
(
'.wrapper-prompt.is-shown .prompt.warning'
).
length
).
toEqual
(
1
);
$
(
'.wrapper-prompt.is-shown .action-primary'
).
click
();
AjaxHelpers
.
expectJsonRequest
(
requests
,
'DELETE'
,
'dummy_change_role_url'
,
{
role
:
null
});
AjaxHelpers
.
respondWithJson
(
requests
,
{
'result'
:
'ok'
});
expect
(
reloadSpy
).
toHaveBeenCalled
();
});
});
});
cms/templates/js/mock/mock-manage-users-lib.underscore
0 → 100644
View file @
d38e69c6
<div class="wrapper-mast wrapper">
<header class="mast has-actions has-subtitle">
<h1 class="page-header">
<small class="subtitle">Settings</small>
<span class="sr">> </span>Instructor Access
</h1>
<nav class="nav-actions">
<h3 class="sr">Page Actions</h3>
<ul>
<li class="nav-item">
<a href="#" class="button new-button create-user-button"><i class="icon-plus"></i> Add Instructor</a>
</li>
</ul>
</nav>
</header>
</div>
<div class="wrapper-content wrapper">
<section class="content">
<article class="content-primary" role="main">
<div class="wrapper-create-element animate wrapper-create-user">
<form class="form-create create-user" id="create-user-form" name="create-user-form">
<div class="wrapper-form">
<h3 class="title">Grant Instructor Access to This Library</h3>
<fieldset class="form-fields">
<legend class="sr">New Instructor Information</legend>
<ol class="list-input">
<li class="field text required create-user-email">
<label for="user-email-input">User's Email Address</label>
<input id="user-email-input" class="user-email-input" name="user-email" type="text" placeholder="example: username@domain.com" value="">
<span class="tip tip-stacked">Please provide the email address of the instructor you'd like to add</span>
</li>
</ol>
</fieldset>
</div>
<div class="actions">
<button class="action action-primary" type="submit">Add User</button>
<button class="action action-secondary action-cancel">Cancel</button>
</div>
</form>
</div>
<ol class="user-list">
<li class="user-item" data-email="honor@example.com">
<span class="wrapper-ui-badge">
<span class="flag flag-role flag-role-staff is-hanging">
<span class="label sr">Current Role:</span>
<span class="value">
Staff
</span>
</span>
</span>
<div class="item-metadata">
<h3 class="user-name">
<span class="user-username">honor</span>
<span class="user-email">
<a class="action action-email" href="mailto:honor@example.com" title="send an email message to honor@example.com">honor@example.com</a>
</span>
</h3>
</div>
<ul class="item-actions user-actions">
<li class="action action-role">
<a href="#" class="make-instructor admin-role add-admin-role">Add Admin Access</span></a>
<a href="#" class="make-user admin-role remove-admin-role">Remove Staff Access</span></a>
</li>
<li class="action action-delete ">
<a href="#" class="delete remove-user action-icon" data-tooltip="Remove this user"><i class="icon-trash"></i><span class="sr">Delete the user, honor</span></a>
</li>
</ul>
</li>
<li class="user-item" data-email="audit@example.com">
<span class="wrapper-ui-badge">
<span class="flag flag-role flag-role-admin is-hanging">
<span class="label sr">Current Role:</span>
<span class="value">
Admin
</span>
</span>
</span>
<div class="item-metadata">
<h3 class="user-name">
<span class="user-username">audit</span>
<span class="user-email">
<a class="action action-email" href="mailto:audit@example.com" title="send an email message to audit@example.com">audit@example.com</a>
</span>
</h3>
</div>
<ul class="item-actions user-actions">
<li class="action action-role">
<a href="#" class="make-staff admin-role remove-admin-role">Remove Admin Access</span></a>
</li>
<li class="action action-delete ">
<a href="#" class="delete remove-user action-icon" data-tooltip="Remove this user"><i class="icon-trash"></i><span class="sr">Delete the user, audit</span></a>
</li>
</ul>
</li>
<li class="user-item" data-email="staff@example.com">
<span class="wrapper-ui-badge">
<span class="flag flag-role flag-role-user is-hanging">
<span class="label sr">Current Role:</span>
<span class="value">
User
</span>
</span>
</span>
<div class="item-metadata">
<h3 class="user-name">
<span class="user-username">staff</span>
<span class="user-email">
<a class="action action-email" href="mailto:staff@example.com" title="send an email message to staff@example.com">staff@example.com</a>
</span>
</h3>
</div>
<ul class="item-actions user-actions">
<li class="action action-role">
<a href="#" class="make-staff admin-role add-admin-role">Add Staff Access</span></a>
</li>
<li class="action action-delete ">
<a href="#" class="delete remove-user action-icon" data-tooltip="Remove this user"><i class="icon-trash"></i><span class="sr">Delete the user, staff</span></a>
</li>
</ul>
</li>
</ol>
</article>
</section>
</div>
common/djangoapps/student/views.py
View file @
d38e69c6
...
@@ -1746,6 +1746,7 @@ def auto_auth(request):
...
@@ -1746,6 +1746,7 @@ def auto_auth(request):
* `staff`: Set to "true" to make the user global staff.
* `staff`: Set to "true" to make the user global staff.
* `course_id`: Enroll the student in the course with `course_id`
* `course_id`: Enroll the student in the course with `course_id`
* `roles`: Comma-separated list of roles to grant the student in the course with `course_id`
* `roles`: Comma-separated list of roles to grant the student in the course with `course_id`
* `no_login`: Define this to create the user but not login
If username, email, or password are not provided, use
If username, email, or password are not provided, use
randomly generated credentials.
randomly generated credentials.
...
@@ -1765,6 +1766,7 @@ def auto_auth(request):
...
@@ -1765,6 +1766,7 @@ def auto_auth(request):
if
course_id
:
if
course_id
:
course_key
=
CourseLocator
.
from_string
(
course_id
)
course_key
=
CourseLocator
.
from_string
(
course_id
)
role_names
=
[
v
.
strip
()
for
v
in
request
.
GET
.
get
(
'roles'
,
''
)
.
split
(
','
)
if
v
.
strip
()]
role_names
=
[
v
.
strip
()
for
v
in
request
.
GET
.
get
(
'roles'
,
''
)
.
split
(
','
)
if
v
.
strip
()]
login_when_done
=
'no_login'
not
in
request
.
GET
# Get or create the user object
# Get or create the user object
post_data
=
{
post_data
=
{
...
@@ -1808,6 +1810,7 @@ def auto_auth(request):
...
@@ -1808,6 +1810,7 @@ def auto_auth(request):
user
.
roles
.
add
(
role
)
user
.
roles
.
add
(
role
)
# Log in as the user
# Log in as the user
if
login_when_done
:
user
=
authenticate
(
username
=
username
,
password
=
password
)
user
=
authenticate
(
username
=
username
,
password
=
password
)
login
(
request
,
user
)
login
(
request
,
user
)
...
@@ -1815,7 +1818,8 @@ def auto_auth(request):
...
@@ -1815,7 +1818,8 @@ def auto_auth(request):
# Provide the user with a valid CSRF token
# Provide the user with a valid CSRF token
# then return a 200 response
# then return a 200 response
success_msg
=
u"Logged in user {0} ({1}) with password {2} and user_id {3}"
.
format
(
success_msg
=
u"{} user {} ({}) with password {} and user_id {}"
.
format
(
u"Logged in"
if
login_when_done
else
"Created"
,
username
,
email
,
password
,
user
.
id
username
,
email
,
password
,
user
.
id
)
)
response
=
HttpResponse
(
success_msg
)
response
=
HttpResponse
(
success_msg
)
...
...
common/test/acceptance/pages/studio/auto_auth.py
View file @
d38e69c6
...
@@ -15,7 +15,7 @@ class AutoAuthPage(PageObject):
...
@@ -15,7 +15,7 @@ class AutoAuthPage(PageObject):
this url will create a user and log them in.
this url will create a user and log them in.
"""
"""
def
__init__
(
self
,
browser
,
username
=
None
,
email
=
None
,
password
=
None
,
staff
=
None
,
course_id
=
None
,
roles
=
None
):
def
__init__
(
self
,
browser
,
username
=
None
,
email
=
None
,
password
=
None
,
staff
=
None
,
course_id
=
None
,
roles
=
None
,
no_login
=
None
):
"""
"""
Auto-auth is an end-point for HTTP GET requests.
Auto-auth is an end-point for HTTP GET requests.
By default, it will create accounts with random user credentials,
By default, it will create accounts with random user credentials,
...
@@ -51,6 +51,9 @@ class AutoAuthPage(PageObject):
...
@@ -51,6 +51,9 @@ class AutoAuthPage(PageObject):
if
roles
is
not
None
:
if
roles
is
not
None
:
self
.
_params
[
'roles'
]
=
roles
self
.
_params
[
'roles'
]
=
roles
if
no_login
:
self
.
_params
[
'no_login'
]
=
True
@property
@property
def
url
(
self
):
def
url
(
self
):
"""
"""
...
@@ -66,7 +69,7 @@ class AutoAuthPage(PageObject):
...
@@ -66,7 +69,7 @@ class AutoAuthPage(PageObject):
def
is_browser_on_page
(
self
):
def
is_browser_on_page
(
self
):
message
=
self
.
q
(
css
=
'BODY'
)
.
text
[
0
]
message
=
self
.
q
(
css
=
'BODY'
)
.
text
[
0
]
match
=
re
.
search
(
r'
Logged in
user ([^$]+) with password ([^$]+) and user_id ([^$]+)$'
,
message
)
match
=
re
.
search
(
r'
(Logged in|Created)
user ([^$]+) with password ([^$]+) and user_id ([^$]+)$'
,
message
)
return
True
if
match
else
False
return
True
if
match
else
False
def
get_user_id
(
self
):
def
get_user_id
(
self
):
...
...
common/test/acceptance/pages/studio/users.py
0 → 100644
View file @
d38e69c6
"""
Page classes to test either the Course Team page or the Library Team page.
"""
from
bok_choy.promise
import
EmptyPromise
from
bok_choy.page_object
import
PageObject
from
...tests.helpers
import
disable_animations
from
.
import
BASE_URL
def
wait_for_ajax_or_reload
(
browser
):
"""
Wait for all ajax requests to finish, OR for the page to reload.
Normal wait_for_ajax() chokes on occasion if the pages reloads,
giving "WebDriverException: Message: u'jQuery is not defined'"
"""
def
_is_ajax_finished
():
""" Wait for jQuery to finish all AJAX calls, if it is present. """
return
browser
.
execute_script
(
"return typeof(jQuery) == 'undefined' || jQuery.active == 0"
)
EmptyPromise
(
_is_ajax_finished
,
"Finished waiting for ajax requests."
)
.
fulfill
()
class
UsersPage
(
PageObject
):
"""
Base class for either the Course Team page or the Library Team page
"""
def
__init__
(
self
,
browser
,
locator
):
super
(
UsersPage
,
self
)
.
__init__
(
browser
)
self
.
locator
=
locator
@property
def
url
(
self
):
"""
URL to this page - override in subclass
"""
raise
NotImplementedError
def
is_browser_on_page
(
self
):
"""
Returns True iff the browser has loaded the page.
"""
return
self
.
q
(
css
=
'body.view-team'
)
.
present
@property
def
users
(
self
):
"""
Return a list of users listed on this page.
"""
return
self
.
q
(
css
=
'.user-list .user-item'
)
.
map
(
lambda
el
:
UserWrapper
(
self
.
browser
,
el
.
get_attribute
(
'data-email'
)))
.
results
@property
def
has_add_button
(
self
):
"""
Is the "New Team Member" button present?
"""
return
self
.
q
(
css
=
'.create-user-button'
)
.
present
def
click_add_button
(
self
):
"""
Click on the "New Team Member" button
"""
self
.
q
(
css
=
'.create-user-button'
)
.
click
()
@property
def
new_user_form_visible
(
self
):
""" Is the new user form visible? """
return
self
.
q
(
css
=
'.form-create.create-user .user-email-input'
)
.
visible
def
set_new_user_email
(
self
,
email
):
""" Set the value of the "New User Email Address" field. """
self
.
q
(
css
=
'.form-create.create-user .user-email-input'
)
.
fill
(
email
)
def
click_submit_new_user_form
(
self
):
""" Submit the "New User" form """
self
.
q
(
css
=
'.form-create.create-user .action-primary'
)
.
click
()
wait_for_ajax_or_reload
(
self
.
browser
)
class
LibraryUsersPage
(
UsersPage
):
"""
Library Team page in Studio
"""
@property
def
url
(
self
):
"""
URL to the "User Access" page for the given library.
"""
return
"{}/library/{}/team/"
.
format
(
BASE_URL
,
unicode
(
self
.
locator
))
class
UserWrapper
(
PageObject
):
"""
A PageObject representing a wrapper around a user listed on the course/library team page.
"""
url
=
None
COMPONENT_BUTTONS
=
{
'basic_tab'
:
'.editor-tabs li.inner_tab_wrap:nth-child(1) > a'
,
'advanced_tab'
:
'.editor-tabs li.inner_tab_wrap:nth-child(2) > a'
,
'save_settings'
:
'.action-save'
,
}
def
__init__
(
self
,
browser
,
email
):
super
(
UserWrapper
,
self
)
.
__init__
(
browser
)
self
.
email
=
email
self
.
selector
=
'.user-list .user-item[data-email="{}"]'
.
format
(
self
.
email
)
def
is_browser_on_page
(
self
):
"""
Sanity check that our wrapper element is on the page.
"""
return
self
.
q
(
css
=
self
.
selector
)
.
present
def
_bounded_selector
(
self
,
selector
):
"""
Return `selector`, but limited to this particular user entry's context
"""
return
'{} {}'
.
format
(
self
.
selector
,
selector
)
@property
def
name
(
self
):
""" Get this user's username, as displayed. """
return
self
.
q
(
css
=
self
.
_bounded_selector
(
'.user-username'
))
.
text
[
0
]
@property
def
role_label
(
self
):
""" Get this user's role, as displayed. """
return
self
.
q
(
css
=
self
.
_bounded_selector
(
'.flag-role .value'
))
.
text
[
0
]
@property
def
is_current_user
(
self
):
""" Does the UI indicate that this is the current user? """
return
self
.
q
(
css
=
self
.
_bounded_selector
(
'.flag-role .msg-you'
))
.
present
@property
def
can_promote
(
self
):
""" Can this user be promoted to a more powerful role? """
return
self
.
q
(
css
=
self
.
_bounded_selector
(
'.add-admin-role'
))
.
present
@property
def
promote_button_text
(
self
):
""" What does the promote user button say? """
return
self
.
q
(
css
=
self
.
_bounded_selector
(
'.add-admin-role'
))
.
text
[
0
]
def
click_promote
(
self
):
""" Click on the button to promote this user to the more powerful role """
self
.
q
(
css
=
self
.
_bounded_selector
(
'.add-admin-role'
))
.
click
()
wait_for_ajax_or_reload
(
self
.
browser
)
@property
def
can_demote
(
self
):
""" Can this user be demoted to a less powerful role? """
return
self
.
q
(
css
=
self
.
_bounded_selector
(
'.remove-admin-role'
))
.
present
@property
def
demote_button_text
(
self
):
""" What does the demote user button say? """
return
self
.
q
(
css
=
self
.
_bounded_selector
(
'.remove-admin-role'
))
.
text
[
0
]
def
click_demote
(
self
):
""" Click on the button to demote this user to the less powerful role """
self
.
q
(
css
=
self
.
_bounded_selector
(
'.remove-admin-role'
))
.
click
()
wait_for_ajax_or_reload
(
self
.
browser
)
@property
def
can_delete
(
self
):
""" Can this user be deleted? """
return
self
.
q
(
css
=
self
.
_bounded_selector
(
'.action-delete:not(.is-disabled) .remove-user'
))
.
present
def
click_delete
(
self
):
""" Click the button to delete this user. """
disable_animations
(
self
)
self
.
q
(
css
=
self
.
_bounded_selector
(
'.remove-user'
))
.
click
()
# We can't use confirm_prompt because its wait_for_ajax is flaky when the page is expected to reload.
self
.
wait_for_element_visibility
(
'.prompt'
,
'Prompt is visible'
)
self
.
wait_for_element_visibility
(
'.prompt .action-primary'
,
'Confirmation button is visible'
)
self
.
q
(
css
=
'.prompt .action-primary'
)
.
click
()
wait_for_ajax_or_reload
(
self
.
browser
)
@property
def
has_no_change_warning
(
self
):
""" Does this have a warning in place of the promote/demote buttons? """
return
self
.
q
(
css
=
self
.
_bounded_selector
(
'.notoggleforyou'
))
.
present
@property
def
no_change_warning_text
(
self
):
""" Text of the warning seen in place of the promote/demote buttons. """
return
self
.
q
(
css
=
self
.
_bounded_selector
(
'.notoggleforyou'
))
.
text
[
0
]
common/test/acceptance/tests/studio/test_studio_library.py
View file @
d38e69c6
...
@@ -5,8 +5,10 @@ from ddt import ddt, data
...
@@ -5,8 +5,10 @@ from ddt import ddt, data
from
.base_studio_test
import
StudioLibraryTest
from
.base_studio_test
import
StudioLibraryTest
from
...fixtures.course
import
XBlockFixtureDesc
from
...fixtures.course
import
XBlockFixtureDesc
from
...pages.studio.auto_auth
import
AutoAuthPage
from
...pages.studio.utils
import
add_component
from
...pages.studio.utils
import
add_component
from
...pages.studio.library
import
LibraryPage
from
...pages.studio.library
import
LibraryPage
from
...pages.studio.users
import
LibraryUsersPage
@ddt
@ddt
...
@@ -306,3 +308,138 @@ class LibraryNavigationTest(StudioLibraryTest):
...
@@ -306,3 +308,138 @@ class LibraryNavigationTest(StudioLibraryTest):
self
.
assertEqual
(
self
.
lib_page
.
xblocks
[
0
]
.
name
,
'1'
)
self
.
assertEqual
(
self
.
lib_page
.
xblocks
[
0
]
.
name
,
'1'
)
self
.
assertEqual
(
self
.
lib_page
.
xblocks
[
-
1
]
.
name
,
'11'
)
self
.
assertEqual
(
self
.
lib_page
.
xblocks
[
-
1
]
.
name
,
'11'
)
self
.
assertEqual
(
self
.
lib_page
.
get_page_number
(),
'1'
)
self
.
assertEqual
(
self
.
lib_page
.
get_page_number
(),
'1'
)
class
LibraryUsersPageTest
(
StudioLibraryTest
):
"""
Test the functionality of the library "Instructor Access" page.
"""
def
setUp
(
self
):
super
(
LibraryUsersPageTest
,
self
)
.
setUp
()
# Create a second user for use in these tests:
AutoAuthPage
(
self
.
browser
,
username
=
"second"
,
email
=
"second@example.com"
,
no_login
=
True
)
.
visit
()
self
.
page
=
LibraryUsersPage
(
self
.
browser
,
self
.
library_key
)
self
.
page
.
visit
()
def
_expect_refresh
(
self
):
"""
Wait for the page to reload.
"""
self
.
page
=
LibraryUsersPage
(
self
.
browser
,
self
.
library_key
)
.
wait_for_page
()
def
test_user_management
(
self
):
"""
Scenario: Ensure that we can edit the permissions of users.
Given I have a library in Studio where I am the only admin
assigned (which is the default for a newly-created library)
And I navigate to Library "Instructor Access" Page in Studio
Then there should be one user listed (myself), and I must
not be able to remove myself or my instructor privilege.
When I click Add Intructor
Then I see a form to complete
When I complete the form and submit it
Then I can see the new user is listed as a "User" of the library
When I click to Add Staff permissions to the new user
Then I can see the new user has staff permissions and that I am now
able to promote them to an Admin or remove their staff permissions.
When I click to Add Admin permissions to the new user
Then I can see the new user has admin permissions and that I can now
remove Admin permissions from either user.
"""
def
check_is_only_admin
(
user
):
"""
Ensure user is an admin user and cannot be removed.
(There must always be at least one admin user.)
"""
self
.
assertIn
(
"admin"
,
user
.
role_label
.
lower
())
self
.
assertFalse
(
user
.
can_promote
)
self
.
assertFalse
(
user
.
can_demote
)
self
.
assertFalse
(
user
.
can_delete
)
self
.
assertTrue
(
user
.
has_no_change_warning
)
self
.
assertIn
(
"Promote another member to Admin to remove admin rights"
,
user
.
no_change_warning_text
)
self
.
assertEqual
(
len
(
self
.
page
.
users
),
1
)
user
=
self
.
page
.
users
[
0
]
self
.
assertTrue
(
user
.
is_current_user
)
check_is_only_admin
(
user
)
# Add a new user:
self
.
assertTrue
(
self
.
page
.
has_add_button
)
self
.
assertFalse
(
self
.
page
.
new_user_form_visible
)
self
.
page
.
click_add_button
()
self
.
assertTrue
(
self
.
page
.
new_user_form_visible
)
self
.
page
.
set_new_user_email
(
'second@example.com'
)
self
.
page
.
click_submit_new_user_form
()
# Check the new user's listing:
def
get_two_users
():
"""
Expect two users to be listed, one being me, and another user.
Returns me, them
"""
users
=
self
.
page
.
users
self
.
assertEqual
(
len
(
users
),
2
)
self
.
assertEqual
(
len
([
u
for
u
in
users
if
u
.
is_current_user
]),
1
)
if
users
[
0
]
.
is_current_user
:
return
users
[
0
],
users
[
1
]
else
:
return
users
[
1
],
users
[
0
]
self
.
_expect_refresh
()
user_me
,
them
=
get_two_users
()
check_is_only_admin
(
user_me
)
self
.
assertIn
(
"user"
,
them
.
role_label
.
lower
())
self
.
assertTrue
(
them
.
can_promote
)
self
.
assertIn
(
"Add Staff Access"
,
them
.
promote_button_text
)
self
.
assertFalse
(
them
.
can_demote
)
self
.
assertTrue
(
them
.
can_delete
)
self
.
assertFalse
(
them
.
has_no_change_warning
)
# Add Staff permissions to the new user:
them
.
click_promote
()
self
.
_expect_refresh
()
user_me
,
them
=
get_two_users
()
check_is_only_admin
(
user_me
)
self
.
assertIn
(
"staff"
,
them
.
role_label
.
lower
())
self
.
assertTrue
(
them
.
can_promote
)
self
.
assertIn
(
"Add Admin Access"
,
them
.
promote_button_text
)
self
.
assertTrue
(
them
.
can_demote
)
self
.
assertIn
(
"Remove Staff Access"
,
them
.
demote_button_text
)
self
.
assertTrue
(
them
.
can_delete
)
self
.
assertFalse
(
them
.
has_no_change_warning
)
# Add Admin permissions to the new user:
them
.
click_promote
()
self
.
_expect_refresh
()
user_me
,
them
=
get_two_users
()
self
.
assertIn
(
"admin"
,
user_me
.
role_label
.
lower
())
self
.
assertFalse
(
user_me
.
can_promote
)
self
.
assertTrue
(
user_me
.
can_demote
)
self
.
assertTrue
(
user_me
.
can_delete
)
self
.
assertFalse
(
user_me
.
has_no_change_warning
)
self
.
assertIn
(
"admin"
,
them
.
role_label
.
lower
())
self
.
assertFalse
(
them
.
can_promote
)
self
.
assertTrue
(
them
.
can_demote
)
self
.
assertIn
(
"Remove Admin Access"
,
them
.
demote_button_text
)
self
.
assertTrue
(
them
.
can_delete
)
self
.
assertFalse
(
them
.
has_no_change_warning
)
# Delete the new user:
them
.
click_delete
()
self
.
_expect_refresh
()
self
.
assertEqual
(
len
(
self
.
page
.
users
),
1
)
user
=
self
.
page
.
users
[
0
]
self
.
assertTrue
(
user
.
is_current_user
)
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