Support students in CreateCourseModal

Since this modal will be used everywhere in Canvas, support
students and users with no enrollments creating courses (when enabled
at the root account). Students will see all accounts where they have
enrollments; users with no enrollments will only see the manually-
created courses subaccount. Don't show homeroom sync options to
students/users with no enrollments. Expose the manually-created
courses subaccount ID/basic info through a new API.

flag = create_course_subaccount_picker
closes LS-2678

Test plan:
 - Enable root account FF: create_course_subaccount_picker
 - In root account settings, allow techers, students, and users with
   no enrollments to create courses
 - Login to k5 dashboard as an admin and click the + (New Subject)
   button
 - Expect to see a manageable_courses network request and a dropdown
   to select an account (along with the checkbox to sync homerooms)
 - Login and open the modal as a teacher
 - Expect to see an enrollments network request and a dropdown with
   all the accounts where the user has a teacher enrollment (and the
   homeroom sync checkbox)
 - Login and open the modal as a student
 - Expect another enrollments network request and a dropdown with all
   their accounts (if there's more than one)
 - Expect to not see the sync options
 - Login as a user with no enrollments
 - Expect a network request to the manually_created_courses_account api
 - Expect to not see a dropdown with accounts or the sync options
 - Disable 'X can create courses' at the root account and expect the
   associated users to no longer see the create course modal at all
 - With FF disabled, expect course creation to work as before

Change-Id: I0e7d49628ce6395fd366037a3134133084fe6275
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/274986
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
Product-Review: Peyton Craighill <pcraighill@instructure.com>
Reviewed-by: Robin Kuss <rkuss@instructure.com>
QA-Review: Robin Kuss <rkuss@instructure.com>
This commit is contained in:
Jackson Howe 2021-10-01 10:56:26 -06:00
parent bbe7c5d357
commit 498aaa11db
21 changed files with 269 additions and 151 deletions

View File

@ -293,7 +293,7 @@ require 'csv'
# }
class AccountsController < ApplicationController
before_action :require_user, :only => [:index, :help_links]
before_action :require_user, :only => [:index, :help_links, :manually_created_courses_account]
before_action :reject_student_view_student
before_action :get_context
before_action :rce_js_env, only: [:settings]
@ -516,6 +516,15 @@ class AccountsController < ApplicationController
render :json => links
end
# @API Get the manually-created courses sub-account for the domain root account
#
# @returns Account
def manually_created_courses_account
account = @domain_root_account.manually_created_courses_account
read_only = !account.grants_right?(@current_user, session, :read)
render :json => account_json(account, @current_user, session, [], read_only)
end
include Api::V1::Course
# @API List active courses in an account

View File

@ -498,6 +498,7 @@ class CoursesController < ApplicationController
format.html {
css_bundle :context_list, :course_list
js_bundle :course_list
js_env({ CREATE_COURSES_PERMISSION: @current_user.create_courses_right(@domain_root_account) })
set_k5_mode(require_k5_theme: true)
@ -887,7 +888,7 @@ class CoursesController < ApplicationController
Auditors::Course.record_published(@course, @current_user, source: :api)
end
# Sync homeroom enrollments and participation if enabled and the course isn't a SIS import
if @course.elementary_enabled? && params[:course][:sync_enrollments_from_homeroom] && params[:course][:homeroom_course_id] && @course.sis_batch_id.blank?
if @course.elementary_enabled? && value_to_boolean(params[:course][:sync_enrollments_from_homeroom]) && params[:course][:homeroom_course_id] && @course.sis_batch_id.blank?
progress = Progress.new(context: @course, tag: :sync_homeroom_enrollments)
progress.user = @current_user
progress.reset!

View File

@ -513,7 +513,8 @@ class UsersController < ApplicationController
STUDENT_PLANNER_ENABLED: planner_enabled?,
STUDENT_PLANNER_COURSES: planner_enabled? && map_courses_for_menu(@current_user.courses_with_primary_enrollment),
STUDENT_PLANNER_GROUPS: planner_enabled? && map_groups_for_planner(@current_user.current_groups),
CAN_ENABLE_K5_DASHBOARD: k5_disabled && k5_user
CAN_ENABLE_K5_DASHBOARD: k5_disabled && k5_user,
CREATE_COURSES_PERMISSION: @current_user.create_courses_right(@domain_root_account)
})
if k5_user?
@ -527,10 +528,6 @@ class UsersController < ApplicationController
SELECTED_CONTEXT_CODES: @current_user.get_preference(:selected_calendar_contexts),
SELECTED_CONTEXTS_LIMIT: @domain_root_account.settings[:calendar_contexts_limit] || 10,
INITIAL_NUM_K5_CARDS: Rails.cache.read(['last_known_k5_cards_count', @current_user.global_id].cache_key) || 5,
PERMISSIONS: {
create_courses_as_admin: @current_user.roles(@domain_root_account).include?('admin'),
create_courses_as_teacher: @domain_root_account.grants_right?(@current_user, session, :create_courses)
},
CAN_ADD_OBSERVEE: @current_user
.profile
.tabs_available(@current_user, :root_account => @domain_root_account)

View File

@ -1316,32 +1316,7 @@ class Account < ActiveRecord::Base
given { |user| self.root_account? && self.cached_all_account_users_for(user).any? }
can :read_terms
#################### Begin legacy permission block #########################
given do |user|
user && !root_account.feature_enabled?(:granular_permissions_manage_courses) &&
self.cached_account_users_for(user).any? do |au|
au.has_permission_to?(self, :manage_courses)
end
end
can :create_courses
##################### End legacy permission block ##########################
given do |user|
result = false
next false if user&.fake_student?
if user && !root_account.site_admin?
scope = root_account.enrollments.active.where(user_id: user)
result = root_account.teachers_can_create_courses? &&
scope.where(:type => ['TeacherEnrollment', 'DesignerEnrollment']).exists?
result ||= root_account.students_can_create_courses? &&
scope.where(:type => ['StudentEnrollment', 'ObserverEnrollment']).exists?
result ||= root_account.no_enrollments_can_create_courses? &&
!scope.exists?
end
result
end
given { |user| user&.create_courses_right(self).present? }
can :create_courses
# allow teachers to view term dates

View File

@ -3250,4 +3250,18 @@ class User < ActiveRecord::Base
def pronouns=(pronouns)
write_attribute(:pronouns, untranslate_pronouns(pronouns))
end
def create_courses_right(account)
return :admin if account.cached_account_users_for(self).any? do |au|
au.has_permission_to?(account, :manage_courses) || au.has_permission_to?(account, :manage_courses_add)
end
return nil if fake_student? || account.root_account.site_admin?
scope = account.root_account.enrollments.active.where(user_id: self)
return :teacher if account.root_account.teachers_can_create_courses? && scope.exists?(type: %w[TeacherEnrollment DesignerEnrollment])
return :student if account.root_account.students_can_create_courses? && scope.exists?(type: %w[StudentEnrollment ObserverEnrollment])
return :no_enrollments if account.root_account.no_enrollments_can_create_courses? && !scope.exists?
nil
end
end

View File

@ -274,7 +274,7 @@
<div class="tall-row">
<div class="nobr">
<%= f.check_box :sync_enrollments_from_homeroom, class: 'sync_enrollments_from_homeroom_checkbox', :disabled => !can_manage || @context.homeroom_course %>
<%= f.label :sync_enrollments_from_homeroom, :en => "Sync enrollments and course start/end dates from homeroom" %><br/>
<%= f.label :sync_enrollments_from_homeroom, :en => "Sync enrollments and subject start/end dates from homeroom" %><br/>
</div>
<div class="sync_enrollments_from_homeroom_select">
<% format_options = options_from_collection_for_select(@homeroom_courses, 'id', 'name', @context.homeroom_course_id) %>

View File

@ -1518,6 +1518,7 @@ CanvasRails::Application.routes.draw do
get 'accounts/:account_id/courses/:id', controller: :courses, action: :show, as: 'account_course_show'
get 'accounts/:account_id/permissions', action: :permissions
get 'accounts/:account_id/settings', action: :show_settings
get 'manually_created_courses_account', action: :manually_created_courses_account
delete 'accounts/:account_id/users/:user_id', action: :remove_user
put 'accounts/:account_id/users/:user_id/restore', action: :restore_user
end

View File

@ -1180,6 +1180,33 @@ describe AccountsController do
end
end
describe "manually_created_courses_account" do
it "returns unauthorized if there's no user" do
get 'manually_created_courses_account'
assert_unauthorized
end
it "returns the account with lots of detail if user has :read on the account" do
account_with_admin_logged_in(active_all: true)
get 'manually_created_courses_account'
expect(response).to be_successful
account = json_parse(response.body)
expect(account['name']).to eq('Manually-Created Courses')
expect(account['default_storage_quota_mb']).to be(500)
end
it "returns limited details about the account to students" do
course_with_student_logged_in(active_all: true)
get 'manually_created_courses_account'
expect(response).to be_successful
account = json_parse(response.body)
expect(account['name']).to eq('Manually-Created Courses')
expect(account['default_storage_quota_mb']).to be_nil
end
end
describe "#account_courses" do
before do
@account = Account.create!

View File

@ -52,6 +52,7 @@ describe CoursesController do
expect(assigns[:current_enrollments][0]).to eql(@enrollment)
expect(assigns[:past_enrollments]).not_to be_nil
expect(assigns[:future_enrollments]).not_to be_nil
expect(assigns[:js_env][:CREATE_COURSES_PERMISSION]).to be_nil
end
it "does not duplicate enrollments in variables" do

View File

@ -2685,37 +2685,6 @@ describe UsersController do
end
end
context "ENV.PERMISSIONS" do
it "sets :create_courses_as_admin to true if user is admin" do
account_admin_user
user_session @user
get 'user_dashboard'
expect(assigns[:js_env][:PERMISSIONS][:create_courses_as_admin]).to be_truthy
end
it "sets only :create_courses_as_teacher to true if user is a teacher and teachers can create courses" do
Account.default.settings[:teachers_can_create_courses] = true
course_with_teacher_logged_in
get 'user_dashboard'
expect(assigns[:js_env][:PERMISSIONS][:create_courses_as_admin]).to be_falsey
expect(assigns[:js_env][:PERMISSIONS][:create_courses_as_teacher]).to be_truthy
end
it "sets :create_courses_as_admin and :create_courses_as_teacher to false if user is a teacher but teachers can't create courses" do
course_with_teacher_logged_in
get 'user_dashboard'
expect(assigns[:js_env][:PERMISSIONS][:create_courses_as_admin]).to be_falsey
expect(assigns[:js_env][:PERMISSIONS][:create_courses_as_teacher]).to be_falsey
end
it "sets :create_courses_as_admin and :create_courses_as_teacher to false if user is a student" do
course_with_student_logged_in
get 'user_dashboard'
expect(assigns[:js_env][:PERMISSIONS][:create_courses_as_admin]).to be_falsey
expect(assigns[:js_env][:PERMISSIONS][:create_courses_as_teacher]).to be_falsey
end
end
context "@cards_prefetch_observer_param" do
before :once do
Account.site_admin.enable_feature!(:k5_parent_support)
@ -2743,6 +2712,15 @@ describe UsersController do
end
end
end
it "sets ENV.CREATE_COURSES_PERMISSION to teacher if user is a teacher and can create courses" do
Account.default.settings[:teachers_can_create_courses] = true
Account.default.save!
course_with_teacher_logged_in(active_all: true)
get 'user_dashboard'
expect(assigns[:js_env][:CREATE_COURSES_PERMISSION]).to be(:teacher)
end
end
describe "#pandata_events_token" do

View File

@ -3675,4 +3675,66 @@ describe User do
expect(@teacher.comment_bank_items).to eq [@c1]
end
end
describe "create_courses_right" do
before :once do
@user = user_factory(active_all: true)
@account = Account.default
end
it "returns :admin for AccountUsers with :manage_courses" do
account_admin_user(user: @user)
expect(@user.create_courses_right(@account)).to be(:admin)
end
it "returns nil for AccountUsers without :manage_courses" do
account_admin_user_with_role_changes(user: @user, role_changes: { manage_courses: false })
expect(@user.create_courses_right(@account)).to be_nil
end
it "returns nil if fake student" do
fake_student = course_factory(active_all: true).student_view_student
expect(fake_student.create_courses_right(@account)).to be_nil
end
it "returns :teacher if user has teacher enrollments iff teachers_can_create_courses?" do
course_with_teacher(user: @user, active_all: true)
expect(@user.create_courses_right(@account)).to be_nil
@account.settings[:teachers_can_create_courses] = true
@account.save!
expect(@user.create_courses_right(@account)).to be(:teacher)
end
it "returns :student if user has student enrollments iff students_can_create_courses?" do
course_with_student(user: @user, active_all: true)
expect(@user.create_courses_right(@account)).to be_nil
@account.settings[:students_can_create_courses] = true
@account.save!
expect(@user.create_courses_right(@account)).to be(:student)
end
it "returns :no_enrollments if user has teacher enrollments iff no_enrollments_can_create_courses?" do
expect(@user.create_courses_right(@account)).to be_nil
@account.settings[:no_enrollments_can_create_courses] = true
@account.save!
expect(@user.create_courses_right(@account)).to be(:no_enrollments)
end
it "does not count deleted teacher enrollments" do
enrollment = course_with_teacher(user: @user)
enrollment.workflow_state = 'deleted'
enrollment.save!
@account.settings[:teachers_can_create_courses] = true
@account.save!
expect(@user.create_courses_right(@account)).to be_nil
end
it "returns :student if user has teacher and student enrollments but teachers_can_create_courses is false" do
course_with_teacher(user: @user, active_all: true)
course_with_student(user: @user, active_all: true)
@account.settings[:students_can_create_courses] = true
@account.save!
expect(@user.create_courses_right(@account)).to be(:student)
end
end
end

View File

@ -290,7 +290,7 @@ module K5DashboardPageObject
end
def sync_enrollments_checkbox_selector
"input + label:contains('Sync enrollments and course start/end dates from homeroom')"
"input + label:contains('Sync enrollments and subject start/end dates from homeroom')"
end
def welcome_title_selector

View File

@ -73,22 +73,13 @@ ready(() => {
const container = document.getElementById('create_subject_modal_container')
if (container) {
startButton.addEventListener('click', () => {
let role
if (ENV.current_user_roles.includes('admin')) {
role = 'admin'
} else if (ENV.current_user_roles.includes('teacher')) {
role = 'teacher'
} else {
// should never get here
return
}
ReactDOM.render(
<CreateCourseModal
isModalOpen
setModalOpen={isOpen => {
if (!isOpen) ReactDOM.unmountComponentAtNode(container)
}}
permissions={role}
permissions={ENV.CREATE_COURSES_PERMISSION}
isK5User={ENV.K5_USER}
/>,
container

View File

@ -270,18 +270,7 @@ function showTodoList() {
const startButton = document.getElementById('start_new_course')
const modalContainer = document.getElementById('create_course_modal_container')
let role
if (ENV.current_user_roles.includes('admin')) {
role = 'admin'
} else if (ENV.current_user_roles.includes('teacher')) {
role = 'teacher'
}
if (
startButton &&
modalContainer &&
role &&
ENV.FEATURES?.create_course_subaccount_picker
) {
if (startButton && modalContainer && ENV.FEATURES?.create_course_subaccount_picker) {
startButton.addEventListener('click', () => {
ReactDOM.render(
<CreateCourseModal
@ -289,7 +278,7 @@ function showTodoList() {
setModalOpen={isOpen => {
if (!isOpen) ReactDOM.unmountComponentAtNode(modalContainer)
}}
permissions={role}
permissions={ENV.CREATE_COURSES_PERMISSION}
isK5User={false} // can't be k5 user if classic dashboard is showing
/>,
modalContainer

View File

@ -35,13 +35,7 @@ ready(() => {
plannerEnabled={ENV.STUDENT_PLANNER_ENABLED}
timeZone={ENV.TIMEZONE}
hideGradesTabForStudents={ENV.HIDE_K5_DASHBOARD_GRADES_TAB}
createPermissions={
ENV.PERMISSIONS?.create_courses_as_admin
? 'admin'
: ENV.PERMISSIONS?.create_courses_as_teacher
? 'teacher'
: 'none'
}
createPermissions={ENV.CREATE_COURSES_PERMISSION}
showImportantDates={!!ENV.FEATURES.important_dates}
selectedContextCodes={ENV.SELECTED_CONTEXT_CODES}
selectedContextsLimit={ENV.SELECTED_CONTEXTS_LIMIT}

View File

@ -81,8 +81,6 @@ const HomeroomPage = ({
</div>
)
const canCreateCourses = createPermissions === 'admin' || createPermissions === 'teacher'
return (
<section
id="dashboard_page_homeroom"
@ -100,7 +98,7 @@ const HomeroomPage = ({
<Flex.Item>
<Heading level="h2">{I18n.t('My Subjects')}</Heading>
</Flex.Item>
{canCreateCourses && (
{createPermissions && (
<Flex.Item>
<Tooltip renderTip={I18n.t('Start a new subject')}>
<IconButton
@ -141,7 +139,7 @@ const HomeroomPage = ({
HomeroomPage.propTypes = {
cards: PropTypes.array,
createPermissions: PropTypes.oneOf(['admin', 'teacher', 'none']).isRequired,
createPermissions: PropTypes.oneOf(['admin', 'teacher', 'student', 'no_enrollments']),
homeroomAnnouncements: PropTypes.array.isRequired,
loadingAnnouncements: PropTypes.bool.isRequired,
visible: PropTypes.bool.isRequired,

View File

@ -389,7 +389,7 @@ K5Dashboard.propTypes = {
assignmentsDueToday: PropTypes.object.isRequired,
assignmentsMissing: PropTypes.object.isRequired,
assignmentsCompletedForToday: PropTypes.object.isRequired,
createPermissions: PropTypes.oneOf(['admin', 'teacher', 'none']).isRequired,
createPermissions: PropTypes.oneOf(['admin', 'teacher', 'student', 'no_enrollments']),
currentUser: PropTypes.shape({
id: PropTypes.string,
display_name: PropTypes.string,

View File

@ -87,8 +87,8 @@ describe('HomeroomPage', () => {
})
describe('start a new subject button', () => {
it('is not present if createPermissions is set to none', () => {
const {queryByText} = render(<HomeroomPage {...getProps({createPermissions: 'none'})} />)
it('is not present if createPermissions is set to null', () => {
const {queryByText} = render(<HomeroomPage {...getProps({createPermissions: null})} />)
expect(queryByText('Open new subject modal')).not.toBeInTheDocument()
})

View File

@ -182,7 +182,7 @@ const defaultProps = {
canDisableElementaryDashboard: false,
currentUser,
currentUserRoles: ['admin'],
createPermissions: 'none',
createPermissions: null,
plannerEnabled: false,
loadAllOpportunities: () => {},
timeZone: defaultEnv.TIMEZONE,

View File

@ -76,7 +76,7 @@ export const CreateCourseModal = ({isModalOpen, setModalOpen, permissions, isK5U
})
}
const teacherFetchOpts = {
const teacherStudentFetchOpts = {
path: '/api/v1/users/self/courses',
success: useCallback(enrollments => {
const accounts = getAccountsFromEnrollments(enrollments)
@ -89,7 +89,8 @@ export const CreateCourseModal = ({isModalOpen, setModalOpen, permissions, isK5U
params: {
per_page: 100,
include: ['account'],
enrollment_type: 'teacher'
// Show teachers only accounts where they have a teacher enrollment
...(permissions === 'teacher' && {enrollment_type: 'teacher'})
}
}
@ -105,11 +106,22 @@ export const CreateCourseModal = ({isModalOpen, setModalOpen, permissions, isK5U
}
}
const noEnrollmentsFetchOpts = {
path: '/api/v1/manually_created_courses_account',
success: useCallback(account => {
setAllAccounts(account)
setSelectedAccount(account[0])
setAccountSearchTerm(account[0].name)
}, [])
}
useFetchApi({
loading: setLoading,
error: useCallback(err => showFlashError(I18n.t('Unable to get accounts'))(err), []),
fetchAllPages: true,
...(permissions === 'teacher' ? teacherFetchOpts : adminFetchOpts)
...(['teacher', 'student'].includes(permissions) && teacherStudentFetchOpts),
...(permissions === 'admin' && adminFetchOpts),
...(permissions === 'no_enrollments' && noEnrollmentsFetchOpts)
})
const handleAccountSelected = id => {
@ -159,7 +171,10 @@ export const CreateCourseModal = ({isModalOpen, setModalOpen, permissions, isK5U
},
error: useCallback(err => showFlashError(I18n.t('Unable to get homerooms'))(err), []),
fetchAllPages: true,
...(permissions === 'teacher' ? teacherHomeroomFetchOpts : adminHomeroomFetchOpts)
// don't let students/users with no enrollments sync homeroom data
forceResult: ['no_enrollments', 'student'].includes(permissions) ? [] : undefined,
...(permissions === 'teacher' && teacherHomeroomFetchOpts),
...(permissions === 'admin' && adminHomeroomFetchOpts)
})
const handleHomeroomSelected = id => {
@ -180,8 +195,10 @@ export const CreateCourseModal = ({isModalOpen, setModalOpen, permissions, isK5U
))
}
// Don't show the account select for teachers with only one account to show
const hideAccountSelect = permissions === 'teacher' && allAccounts?.length === 1
// Don't show the account select for non-admins with only one account to show
const hideAccountSelect = permissions !== 'admin' && allAccounts?.length === 1
// Don't show homeroom sync to non-k5 users or to students/users with no enrollments
const showHomeroomSyncOptions = isK5User && ['admin', 'teacher'].includes(permissions)
return (
<Modal label={modalLabel} open={isModalOpen} size="small" onDismiss={clearModal}>
@ -210,15 +227,15 @@ export const CreateCourseModal = ({isModalOpen, setModalOpen, permissions, isK5U
{accountOptions}
</CanvasAsyncSelect>
)}
{isK5User && (
{showHomeroomSyncOptions && (
<Checkbox
label={I18n.t('Sync enrollments and course start/end dates from homeroom')}
label={I18n.t('Sync enrollments and subject start/end dates from homeroom')}
value="syncHomeroomEnrollments"
checked={syncHomeroomEnrollments}
onChange={event => setSyncHomeroomEnrollments(event.target.checked)}
/>
)}
{isK5User && syncHomeroomEnrollments && (
{showHomeroomSyncOptions && syncHomeroomEnrollments && (
<SimpleSelect
data-testid="homeroom-select"
renderLabel={I18n.t('Select a homeroom')}
@ -265,6 +282,6 @@ export const CreateCourseModal = ({isModalOpen, setModalOpen, permissions, isK5U
CreateCourseModal.propTypes = {
isModalOpen: PropTypes.bool.isRequired,
setModalOpen: PropTypes.func.isRequired,
permissions: PropTypes.oneOf(['admin', 'teacher']).isRequired,
permissions: PropTypes.oneOf(['admin', 'teacher', 'student', 'no_enrollments']).isRequired,
isK5User: PropTypes.bool.isRequired
}

View File

@ -65,10 +65,20 @@ const ENROLLMENTS = [
}
]
const MCC_ACCOUNT = {
id: 3,
name: 'Manually-Created Courses',
workflow_state: 'active'
}
const MANAGEABLE_COURSES_URL = '/api/v1/manageable_accounts?per_page=100'
const ENROLLMENTS_URL = encodeURI(
const TEACHER_ENROLLMENTS_URL = encodeURI(
'/api/v1/users/self/courses?per_page=100&include[]=account&enrollment_type=teacher'
)
const STUDENT_ENROLLMENTS_URL = encodeURI(
'/api/v1/users/self/courses?per_page=100&include[]=account'
)
const MCC_ACCOUNT_URL = 'api/v1/manually_created_courses_account'
describe('CreateCourseModal', () => {
const setModalOpen = jest.fn()
@ -101,7 +111,7 @@ describe('CreateCourseModal', () => {
).toBeInTheDocument()
expect(getByLabelText('Subject Name')).toBeInTheDocument()
expect(
getByLabelText('Sync enrollments and course start/end dates from homeroom')
getByLabelText('Sync enrollments and subject start/end dates from homeroom')
).toBeInTheDocument()
})
})
@ -194,44 +204,98 @@ describe('CreateCourseModal', () => {
expect(getByRole('button', {name: 'Cancel'})).not.toBeDisabled()
})
it('fetches accounts from enrollments api if permission is set to teacher', async () => {
fetchMock.get(ENROLLMENTS_URL, ENROLLMENTS)
const {getByText, getByLabelText} = render(
<CreateCourseModal {...getProps({permissions: 'teacher'})} />
)
await waitFor(() => expect(getByLabelText('Subject Name')).toBeInTheDocument())
act(() => getByLabelText('Which account will this subject be associated with?').click())
expect(getByText('Orange Elementary')).toBeInTheDocument()
expect(getByText('Clark HS')).toBeInTheDocument()
describe('with teacher permission', () => {
it('fetches accounts from enrollments api', async () => {
fetchMock.get(TEACHER_ENROLLMENTS_URL, ENROLLMENTS)
const {getByText, getByLabelText} = render(
<CreateCourseModal {...getProps({permissions: 'teacher'})} />
)
await waitFor(() => expect(getByLabelText('Subject Name')).toBeInTheDocument())
act(() => getByLabelText('Which account will this subject be associated with?').click())
expect(getByText('Orange Elementary')).toBeInTheDocument()
expect(getByText('Clark HS')).toBeInTheDocument()
})
it('hides the account select if there is only one enrollment', async () => {
fetchMock.get(TEACHER_ENROLLMENTS_URL, [ENROLLMENTS[0]])
const {queryByText, getByLabelText} = render(
<CreateCourseModal {...getProps({permissions: 'teacher'})} />
)
await waitFor(() => expect(getByLabelText('Subject Name')).toBeInTheDocument())
expect(
queryByText('Which account will this subject be associated with?')
).not.toBeInTheDocument()
})
it("doesn't break if the user has restricted enrollments", async () => {
fetchMock.get(TEACHER_ENROLLMENTS_URL, [
...ENROLLMENTS,
{
id: 1033,
access_restricted_by_date: true
}
])
const {getByLabelText, queryByText, getByText} = render(
<CreateCourseModal {...getProps({permissions: 'teacher'})} />
)
await waitFor(() => expect(getByLabelText('Subject Name')).toBeInTheDocument())
expect(queryByText('Unable to get accounts')).not.toBeInTheDocument()
act(() => getByLabelText('Which account will this subject be associated with?').click())
expect(getByText('Orange Elementary')).toBeInTheDocument()
expect(getByText('Clark HS')).toBeInTheDocument()
})
})
it('hides the account select for teachers with only one enrollment', async () => {
fetchMock.get(ENROLLMENTS_URL, [ENROLLMENTS[0]])
const {queryByText, getByLabelText} = render(
<CreateCourseModal {...getProps({permissions: 'teacher'})} />
)
await waitFor(() => expect(getByLabelText('Subject Name')).toBeInTheDocument())
expect(
queryByText('Which account will this subject be associated with?')
).not.toBeInTheDocument()
describe('with student permission', () => {
beforeEach(() => {
fetchMock.get(STUDENT_ENROLLMENTS_URL, ENROLLMENTS)
})
it('fetches accounts from enrollments api', async () => {
const {findByLabelText, getByLabelText, getByText} = render(
<CreateCourseModal {...getProps({permissions: 'student'})} />
)
expect(await findByLabelText('Subject Name')).toBeInTheDocument()
act(() => getByLabelText('Which account will this subject be associated with?').click())
expect(getByText('Orange Elementary')).toBeInTheDocument()
})
it("doesn't show the homeroom sync options", async () => {
const {findByLabelText, queryByText} = render(
<CreateCourseModal {...getProps({permissions: 'student'})} />
)
expect(await findByLabelText('Subject Name')).toBeInTheDocument()
expect(
queryByText('Sync enrollments and subject start/end dates from homeroom')
).not.toBeInTheDocument()
expect(queryByText('Select a homeroom')).not.toBeInTheDocument()
})
})
it("doesn't break if the user has restricted enrollments", async () => {
fetchMock.get(ENROLLMENTS_URL, [
...ENROLLMENTS,
{
id: 1033,
access_restricted_by_date: true
}
])
const {getByLabelText, queryByText, getByText} = render(
<CreateCourseModal {...getProps({permissions: 'teacher'})} />
)
await waitFor(() => expect(getByLabelText('Subject Name')).toBeInTheDocument())
expect(queryByText('Unable to get accounts')).not.toBeInTheDocument()
act(() => getByLabelText('Which account will this subject be associated with?').click())
expect(getByText('Orange Elementary')).toBeInTheDocument()
expect(getByText('Clark HS')).toBeInTheDocument()
describe('with no_enrollments permission', () => {
beforeEach(() => {
fetchMock.get(MCC_ACCOUNT_URL, MCC_ACCOUNT)
})
it('uses the manually_created_courses_account api to get the right account', async () => {
const {findByLabelText} = render(
<CreateCourseModal {...getProps({permissions: 'no_enrollments'})} />
)
expect(await findByLabelText('Subject Name')).toBeInTheDocument()
})
it("doesn't show the homeroom sync options or account dropdown", async () => {
const {findByLabelText, queryByText} = render(
<CreateCourseModal {...getProps({permissions: 'no_enrollments'})} />
)
expect(await findByLabelText('Subject Name')).toBeInTheDocument()
expect(
queryByText('Sync enrollments and subject start/end dates from homeroom')
).not.toBeInTheDocument()
expect(
queryByText('Which account will this subject be associated with?')
).not.toBeInTheDocument()
})
})
describe('with isK5User set to false', () => {
@ -245,7 +309,7 @@ describe('CreateCourseModal', () => {
)
expect(await findByLabelText('Course Name')).toBeInTheDocument()
expect(
queryByText('Sync enrollments and course start/end dates from homeroom')
queryByText('Sync enrollments and subject start/end dates from homeroom')
).not.toBeInTheDocument()
expect(queryByText('Select a homeroom')).not.toBeInTheDocument()
})