Fix bugquest bugs

Hide TeachersContactModal after sending message

Fix GET /db/level/:handle/session, more extensively test

Fix EnrollmentView number of students input to stop losing focus on input

Fix EnrollmentsView syntax

Fix ActivateLicensesModal "Get Enrollments" button when already in the enrollments page

Update EnrollmentsView with new credit numbers when ActivateLicensesModal closes

Hide search box in TeacherClassView "Enrollment Status" tab

Tweak EnrollmentsView styling

Fix EnrollmentsView tests

Fix AnalyticsView

Make EnrollmentsView more explicitly handle undefined and empty array prepaid groups

Remove log

CoursesView handles JoinClassModal cancel

Re-enable EditStudentModal set password button when the form changes

Fix course instance tests, next level endpoint bug

Fix EditStudentModal tests
This commit is contained in:
Scott Erickson 2016-05-23 10:26:34 -07:00 committed by phoenixeliot
parent 3d705e5d70
commit 8dbc86ca04
19 changed files with 111 additions and 46 deletions

View file

@ -32,9 +32,9 @@
border-radius: 5px border-radius: 5px
#students-input #students-input
width: 180px width: 220px
height: 80px height: 80px
font-size: 60px font-size: 50px
&::-webkit-inner-spin-button, &::-webkit-outer-spin-button &::-webkit-inner-spin-button, &::-webkit-outer-spin-button
-webkit-appearance: none -webkit-appearance: none

View file

@ -48,14 +48,14 @@ block content
.row.m-t-3 .row.m-t-3
if anyPrepaids if anyPrepaids
#prepaids-col.col-md-9 #prepaids-col.col-md-9
if available if _.size(available) > 0
h5.m-b-1(data-i18n="teacher.available_credits") h5.m-b-1(data-i18n="teacher.available_credits")
.row .row
for prepaid in available for prepaid in available
.col-sm-4.col-xs-6 .col-sm-4.col-xs-6
+prepaidCard(prepaid) +prepaidCard(prepaid)
if pending if _.size(pending) > 0
h5.m-b-1.m-t-3(data-i18n="teacher.pending_credits") h5.m-b-1.m-t-3(data-i18n="teacher.pending_credits")
.row .row
for prepaid in pending for prepaid in pending

View file

@ -378,14 +378,17 @@ mixin bulkAssignControls
span(data-i18n='teacher.enroll_selected_students') span(data-i18n='teacher.enroll_selected_students')
mixin enrollmentStatusTab mixin enrollmentStatusTab
form.form-inline.text-center.m-t-3 // TODO: Have search input in all tabs
#search-form-group.form-group
label(for="student-search") Search for student:
input#student-search.form-control.m-l-1(type="search")
span.glyphicon.glyphicon-search.form-control-feedback
table.table#enrollment-status-table.table-condensed //form.form-inline.text-center.m-t-3
// #search-form-group.form-group
// label(for="student-search") Search for student:
// input#student-search.form-control.m-l-1(type="search")
// span.glyphicon.glyphicon-search.form-control-feedback
table.table#enrollment-status-table.table-condensed.m-t-3
thead thead
// Checkbox code works, but don't need it yet.
//th.checkbox-col.select-all //th.checkbox-col.select-all
.checkbox-flat .checkbox-flat
input(type='checkbox' id='checkbox-all-students') input(type='checkbox' id='checkbox-all-students')

View file

@ -7,28 +7,28 @@ block modal-header-content
block modal-body-content block modal-body-content
p Send us a message and our classroom success team will be in touch to help find the best solution for your students' needs! p Send us a message and our classroom success team will be in touch to help find the best solution for your students' needs!
form form
- var sending = view.state.get('sendingState') === 'sending'; - var sending = view.state.get('sendingState') === 'sending'
- var sent = view.state.get('sendingState') === 'sent';
- var values = view.state.get('formValues'); - var values = view.state.get('formValues');
- var errors = view.state.get('formErrors'); - var errors = view.state.get('formErrors');
.form-group(class=errors.email ? 'has-error' : '') .form-group(class=errors.email ? 'has-error' : '')
label.control-label(for="email" data-i18n="general.email") label.control-label(for="email" data-i18n="general.email")
+formErrors(errors.email) +formErrors(errors.email)
input.form-control(name="email", type="email", value=values.email || '', tabindex=1, disabled=sending) input.form-control(name="email", type="email", value=values.email || '', tabindex=1, disabled=sending || sent)
.form-group(class=errors.message ? 'has-error' : '') .form-group(class=errors.message ? 'has-error' : '')
label.control-label(for="message" data-i18n="general.message") label.control-label(for="message" data-i18n="general.message")
+formErrors(errors.message) +formErrors(errors.message)
textarea.form-control(name="message", tabindex=1 disabled=sending)= values.message textarea.form-control(name="message", tabindex=1 disabled=sending || sent)= values.message
if view.state.get('sendingState') === 'error' if view.state.get('sendingState') === 'error'
.alert.alert-danger Could not send message. .alert.alert-danger Could not send message.
if view.state.get('sendingState') === 'sent' if sent
.alert.alert-success Message sent! .alert.alert-success Message sent!
.text-right .text-right
- var sent = view.state.get('sendingState') === 'sent';
button#submit-btn.btn.btn-navy.btn-lg(type='submit' disabled=sending || sent) Submit button#submit-btn.btn.btn-navy.btn-lg(type='submit' disabled=sending || sent) Submit
block modal-footer block modal-footer

View file

@ -290,7 +290,7 @@ module.exports = class AnalyticsView extends RootView
prepaidUserMap = {} prepaidUserMap = {}
for user in data.students for user in data.students
continue unless studentPaidStatusMap[user._id] continue unless studentPaidStatusMap[user._id]
if prepaidID = user.coursePrepaidID or user.course.coursePrepaid?._id # TODO: make sure this works for coursePrepaid if prepaidID = user.coursePrepaidID or user.coursePrepaid?._id
studentPaidStatusMap[user._id] = 'paid' studentPaidStatusMap[user._id] = 'paid'
prepaidUserMap[prepaidID] ?= [] prepaidUserMap[prepaidID] ?= []
prepaidUserMap[prepaidID].push(user._id) prepaidUserMap[prepaidID].push(user._id)

View file

@ -16,6 +16,7 @@ module.exports = class ActivateLicensesModal extends ModalView
'change input[type="checkbox"][name="user"]': 'updateSelectedStudents' 'change input[type="checkbox"][name="user"]': 'updateSelectedStudents'
'change select.classroom-select': 'replaceStudentList' 'change select.classroom-select': 'replaceStudentList'
'submit form': 'onSubmitForm' 'submit form': 'onSubmitForm'
'click #get-more-licenses-btn': 'onClickGetMoreLicensesButton'
getInitialState: (options) -> getInitialState: (options) ->
selectedUsers = options.selectedUsers or options.users selectedUsers = options.selectedUsers or options.users
@ -113,3 +114,6 @@ module.exports = class ActivateLicensesModal extends ModalView
finishRedeemUsers: -> finishRedeemUsers: ->
@trigger 'redeem-users', @state.get('selectedUsers') @trigger 'redeem-users', @state.get('selectedUsers')
onClickGetMoreLicensesButton: ->
@hide?() # In case this is opened in /teachers/enrollments itself, otherwise the button does nothing

View file

@ -102,6 +102,9 @@ module.exports = class CoursesView extends RootView
@openModalView modal @openModalView modal
@listenTo modal, 'join:success', @onJoinClassroomSuccess @listenTo modal, 'join:success', @onJoinClassroomSuccess
@listenTo modal, 'join:error', @onJoinClassroomError @listenTo modal, 'join:error', @onJoinClassroomError
@listenTo modal, 'hidden', ->
@state = null
@renderSelectors '#join-class-form'
onJoinClassroomError: (classroom, jqxhr, options) -> onJoinClassroomError: (classroom, jqxhr, options) ->
@state = null @state = null

View file

@ -44,8 +44,9 @@ module.exports = class EnrollmentsView extends RootView
@prepaids.comparator = '_id' @prepaids.comparator = '_id'
@supermodel.trackRequest @prepaids.fetchByCreator(me.id) @supermodel.trackRequest @prepaids.fetchByCreator(me.id)
@debouncedRender = _.debounce @render, 0 @debouncedRender = _.debounce @render, 0
@listenTo @prepaids, 'all', -> @state.set('prepaidGroups', @prepaids.groupBy((p) -> p.status())) @listenTo @prepaids, 'sync', @updatePrepaidGroups
@listenTo(@state, 'all', @debouncedRender) @listenTo(@state, 'all', @debouncedRender)
@listenTo(me, 'change:enrollmentRequestSent', @debouncedRender)
onceClassroomsSync: -> onceClassroomsSync: ->
for classroom in @classrooms.models for classroom in @classrooms.models
@ -56,6 +57,9 @@ module.exports = class EnrollmentsView extends RootView
@state.set('totalCourses', @courses.size()) @state.set('totalCourses', @courses.size())
super() super()
updatePrepaidGroups: ->
@state.set('prepaidGroups', @prepaids.groupBy((p) -> p.status()))
calculateEnrollmentStats: -> calculateEnrollmentStats: ->
@removeDeletedStudents() @removeDeletedStudents()
@ -95,10 +99,13 @@ module.exports = class EnrollmentsView extends RootView
if input isnt "" and (parseFloat(input) isnt parseInt(input) or _.isNaN parseInt(input)) if input isnt "" and (parseFloat(input) isnt parseInt(input) or _.isNaN parseInt(input))
@$('#students-input').val(@state.get('numberOfStudents')) @$('#students-input').val(@state.get('numberOfStudents'))
else else
@state.set('numberOfStudents', Math.max(parseInt(@$('#students-input').val()) or 0, 0)) @state.set({'numberOfStudents': Math.max(parseInt(@$('#students-input').val()) or 0, 0)}, {silent: true}) # do not re-render
numberOfStudentsIsValid: -> 0 < @get('numberOfStudents') < 100000 numberOfStudentsIsValid: -> 0 < @get('numberOfStudents') < 100000
onClickEnrollStudentsButton: -> onClickEnrollStudentsButton: ->
modal = new ActivateLicensesModal({ selectedUsers: @notEnrolledUsers, users: @members }) modal = new ActivateLicensesModal({ selectedUsers: @notEnrolledUsers, users: @members })
@openModalView(modal) @openModalView(modal)
modal.once 'hidden', =>
@prepaids.add(modal.prepaids.models, { merge: true })
@debouncedRender() # Because one changed model does not a collection update make

View file

@ -272,7 +272,6 @@ module.exports = class TeacherClassView extends RootView
@students.sort() @students.sort()
onKeyPressStudentSearch: (e) -> onKeyPressStudentSearch: (e) ->
console.log 'emit event'
@state.set('searchTerm', $(e.target).val()) @state.set('searchTerm', $(e.target).val())
getSelectedStudentIDs: -> getSelectedStudentIDs: ->

View file

@ -37,4 +37,9 @@ module.exports = class EditStudentModal extends ModalView
@classroom.setStudentPassword(@user, @state.get('newPassword')) @classroom.setStudentPassword(@user, @state.get('newPassword'))
onChangeNewPasswordInput: (e) -> onChangeNewPasswordInput: (e) ->
@state.set { newPassword: $(e.currentTarget).val() }, { silent: true } @state.set {
newPassword: $(e.currentTarget).val()
emailSent: false
passwordChanged: false
}, { silent: true }
@renderSelectors('.change-password-btn')

View file

@ -10,7 +10,6 @@ module.exports = class TeachersContactModal extends ModalView
events: events:
'submit form': 'onSubmitForm' 'submit form': 'onSubmitForm'
'change form': 'onChangeForm'
initialize: (options={}) -> initialize: (options={}) ->
@state = new State({ @state = new State({
@ -40,10 +39,6 @@ module.exports = class TeachersContactModal extends ModalView
@state.set('formValues', { email, message }) @state.set('formValues', { email, message })
super() super()
onChangeForm: ->
# Want to re-render without losing form focus. TODO: figure out how in state system.
@$('#submit-btn').attr('disabled', false)
onSubmitForm: (e) -> onSubmitForm: (e) ->
e.preventDefault() e.preventDefault()
return if @state.get('sendingState') is 'sending' return if @state.get('sendingState') is 'sending'
@ -64,7 +59,12 @@ module.exports = class TeachersContactModal extends ModalView
contact.send({ contact.send({
data data
context: @ context: @
success: -> @state.set({ sendingState: 'sent' }) success: ->
@state.set({ sendingState: 'sent' })
me.set('enrollmentRequestSent', true)
setTimeout(=>
@hide?()
, 3000)
error: -> @state.set({ sendingState: 'error' }) error: -> @state.set({ sendingState: 'error' })
}) })

View file

@ -98,7 +98,7 @@ module.exports =
throw new errors.NotFound('Level original ObjectId not found in Classroom courses') throw new errors.NotFound('Level original ObjectId not found in Classroom courses')
if not nextLevelOriginal if not nextLevelOriginal
res.status(200).send({}) return res.status(200).send({})
dbq = Level.findOne({original: mongoose.Types.ObjectId(nextLevelOriginal)}) dbq = Level.findOne({original: mongoose.Types.ObjectId(nextLevelOriginal)})
dbq.sort({ 'version.major': -1, 'version.minor': -1 }) dbq.sort({ 'version.major': -1, 'version.minor': -1 })
@ -137,7 +137,7 @@ module.exports =
for courseInstance in courseInstances for courseInstance in courseInstances
if members = courseInstance.get('members') if members = courseInstance.get('members')
userIDs.push(userID) for userID in members userIDs.push(userID) for userID in members
users = yield User.find({_id: {$in: userIDs}}, {coursePrepaid: 1}) users = yield User.find({_id: {$in: userIDs}}, {coursePrepaid: 1, coursePrepaidID: 1})
prepaidIDs = [] prepaidIDs = []
for user in users for user in users

View file

@ -50,12 +50,13 @@ module.exports =
courseID = null courseID = null
classroomMap = {} classroomMap = {}
classroomMap[classroom.id] = classroom for classroom in classrooms classroomMap[classroom.id] = classroom for classroom in classrooms
levelOriginal = level.get('original')
for courseInstance in courseInstances for courseInstance in courseInstances
classroom = classroomMap[courseInstance.get('classroomID').toString()] classroom = classroomMap[courseInstance.get('classroomID').toString()]
courseID = courseInstance.get('courseID') courseID = courseInstance.get('courseID')
classroomCourse = _.find(classroom.get('courses'), (c) -> c._id.equals(courseID)) classroomCourse = _.find(classroom.get('courses'), (c) -> c._id.equals(courseID))
for courseLevel in classroomCourse.levels for courseLevel in classroomCourse.levels
if courseLevel.original.equals(level._id) if courseLevel.original.equals(levelOriginal)
classroomWithLevel = classroom classroomWithLevel = classroom
break break
break if classroomWithLevel break if classroomWithLevel
@ -67,7 +68,7 @@ module.exports =
unless course.get('free') or req.user.isEnrolled() unless course.get('free') or req.user.isEnrolled()
throw new errors.PaymentRequired('You must be enrolled to access this content') throw new errors.PaymentRequired('You must be enrolled to access this content')
lang = classroomWithLevel.get('aceConfig').language lang = classroomWithLevel.get('aceConfig')?.language
attrs.codeLanguage = lang if lang attrs.codeLanguage = lang if lang
else else

View file

@ -73,7 +73,7 @@ module.exports.setup = (app) ->
app.get('/db/course/:handle', mw.rest.getByHandle(Course)) app.get('/db/course/:handle', mw.rest.getByHandle(Course))
app.get('/db/course/:handle/levels/:levelOriginal/next', mw.courses.fetchNextLevel) app.get('/db/course/:handle/levels/:levelOriginal/next', mw.courses.fetchNextLevel)
app.get('/db/course_instance/-/recent', mw.auth.checkHasPermission(['admin']), mw.courseInstances.fetchRecent) app.post('/db/course_instance/-/recent', mw.auth.checkHasPermission(['admin']), mw.courseInstances.fetchRecent)
app.get('/db/course_instance/:handle/levels/:levelOriginal/next', mw.courseInstances.fetchNextLevel) app.get('/db/course_instance/:handle/levels/:levelOriginal/next', mw.courseInstances.fetchNextLevel)
app.post('/db/course_instance/:handle/members', mw.auth.checkLoggedIn(), mw.courseInstances.addMembers) app.post('/db/course_instance/:handle/members', mw.auth.checkLoggedIn(), mw.courseInstances.addMembers)
app.get('/db/course_instance/:handle/classroom', mw.auth.checkLoggedIn(), mw.courseInstances.fetchClassroom) app.get('/db/course_instance/:handle/classroom', mw.auth.checkLoggedIn(), mw.courseInstances.fetchClassroom)

View file

@ -361,7 +361,7 @@ describe 'GET /db/course_instance/:handle/classroom', ->
expect(res.statusCode).toBe(403) expect(res.statusCode).toBe(403)
done() done()
describe 'GET /db/course_instance/-/recent', -> describe 'POST /db/course_instance/-/recent', ->
url = getURL('/db/course_instance/-/recent') url = getURL('/db/course_instance/-/recent')
@ -383,7 +383,7 @@ describe 'GET /db/course_instance/-/recent', ->
done() done()
it 'returns all non-HoC course instances and their related users and prepaids', utils.wrap (done) -> it 'returns all non-HoC course instances and their related users and prepaids', utils.wrap (done) ->
[res, body] = yield request.getAsync(url, { json: true }) [res, body] = yield request.postAsync(url, { json: true })
expect(res.statusCode).toBe(200) expect(res.statusCode).toBe(200)
expect(res.body.courseInstances[0]._id).toBe(@courseInstance.id) expect(res.body.courseInstances[0]._id).toBe(@courseInstance.id)
expect(res.body.students[0]._id).toBe(@student.id) expect(res.body.students[0]._id).toBe(@student.id)
@ -393,23 +393,23 @@ describe 'GET /db/course_instance/-/recent', ->
it 'returns course instances within a specified range', utils.wrap (done) -> it 'returns course instances within a specified range', utils.wrap (done) ->
startDay = moment().subtract(1, 'day').format('YYYY-MM-DD') startDay = moment().subtract(1, 'day').format('YYYY-MM-DD')
endDay = moment().add(1, 'day').format('YYYY-MM-DD') endDay = moment().add(1, 'day').format('YYYY-MM-DD')
[res, body] = yield request.getAsync(url, { json: { startDay, endDay } }) [res, body] = yield request.postAsync(url, { json: { startDay, endDay } })
expect(res.body.courseInstances.length).toBe(1) expect(res.body.courseInstances.length).toBe(1)
startDay = moment().add(1, 'day').format('YYYY-MM-DD') startDay = moment().add(1, 'day').format('YYYY-MM-DD')
endDay = moment().add(2, 'day').format('YYYY-MM-DD') endDay = moment().add(2, 'day').format('YYYY-MM-DD')
[res, body] = yield request.getAsync(url, { json: { startDay, endDay } }) [res, body] = yield request.postAsync(url, { json: { startDay, endDay } })
expect(res.body.courseInstances.length).toBe(0) expect(res.body.courseInstances.length).toBe(0)
startDay = moment().subtract(2, 'day').format('YYYY-MM-DD') startDay = moment().subtract(2, 'day').format('YYYY-MM-DD')
endDay = moment().subtract(1, 'day').format('YYYY-MM-DD') endDay = moment().subtract(1, 'day').format('YYYY-MM-DD')
[res, body] = yield request.getAsync(url, { json: { startDay, endDay } }) [res, body] = yield request.postAsync(url, { json: { startDay, endDay } })
expect(res.body.courseInstances.length).toBe(0) expect(res.body.courseInstances.length).toBe(0)
done() done()
it 'returns 403 if not an admin', utils.wrap (done) -> it 'returns 403 if not an admin', utils.wrap (done) ->
yield utils.loginUser(@teacher) yield utils.loginUser(@teacher)
[res, body] = yield request.getAsync(url, { json: true }) [res, body] = yield request.postAsync(url, { json: true })
expect(res.statusCode).toBe(403) expect(res.statusCode).toBe(403)
done() done()

View file

@ -8,6 +8,7 @@ User = require '../../../server/models/User'
request = require '../request' request = require '../request'
utils = require '../utils' utils = require '../utils'
moment = require 'moment' moment = require 'moment'
mongoose = require 'mongoose'
describe 'Level', -> describe 'Level', ->
@ -42,13 +43,18 @@ describe 'Level', ->
describe 'GET /db/level/:handle/session', -> describe 'GET /db/level/:handle/session', ->
describe 'when level is a course level', -> describe 'when level IS a course level', ->
beforeEach utils.wrap (done) -> beforeEach utils.wrap (done) ->
yield utils.clearModels([Campaign, Course, CourseInstance, Level, User]) yield utils.clearModels([Campaign, Course, CourseInstance, Level, User])
admin = yield utils.initAdmin() admin = yield utils.initAdmin()
yield utils.loginUser(admin) yield utils.loginUser(admin)
@level = yield utils.makeLevel({type: 'course'}) @level = yield utils.makeLevel({type: 'course'})
# To ensure test compares original, not id, make them different. TODO: Make factories do this normally?
@level.set('original', new mongoose.Types.ObjectId())
@level.save()
@campaign = yield utils.makeCampaign({}, {levels: [@level]}) @campaign = yield utils.makeCampaign({}, {levels: [@level]})
@course = yield utils.makeCourse({free: true}, {campaign: @campaign}) @course = yield utils.makeCourse({free: true}, {campaign: @campaign})
@student = yield utils.initUser({role: 'student'}) @student = yield utils.initUser({role: 'student'})
@ -67,6 +73,14 @@ describe 'GET /db/level/:handle/session', ->
expect(body.codeLanguage).toBe('javascript') expect(body.codeLanguage).toBe('javascript')
done() done()
it 'works if the classroom has no aceConfig', utils.wrap (done) ->
@classroom.set('aceConfig', undefined)
yield @classroom.save()
[res, body] = yield request.getAsync { uri: @url, json: true }
expect(res.statusCode).toBe(200)
expect(body.codeLanguage).toBe('python')
done()
it 'returns 402 if the user is not in a course with that level', utils.wrap (done) -> it 'returns 402 if the user is not in a course with that level', utils.wrap (done) ->
otherStudent = yield utils.initUser({role: 'student'}) otherStudent = yield utils.initUser({role: 'student'})
yield utils.loginUser(otherStudent) yield utils.loginUser(otherStudent)
@ -136,3 +150,31 @@ describe 'GET /db/level/:handle/session', ->
[res, body] = yield request.getAsync { uri: @url, json: true } [res, body] = yield request.getAsync { uri: @url, json: true }
expect(body._id).toBe(sessionID) expect(body._id).toBe(sessionID)
done() done()
describe 'when the level is not free', ->
beforeEach utils.wrap (done) ->
yield @level.update({$set: {requiresSubscription: true}})
done()
it 'returns 402 for normal users', utils.wrap (done) ->
[res, body] = yield request.getAsync { uri: @url, json: true }
expect(res.statusCode).toBe(402)
done()
it 'returns 200 for admins', utils.wrap (done) ->
yield @player.update({$set: {permissions: ['admin']}})
[res, body] = yield request.getAsync { uri: @url, json: true }
expect(res.statusCode).toBe(200)
done()
it 'returns 200 for adventurer levels', utils.wrap (done) ->
yield @level.update({$set: {adventurer: true}})
[res, body] = yield request.getAsync { uri: @url, json: true }
expect(res.statusCode).toBe(200)
done()
it 'returns 200 for subscribed users', utils.wrap (done) ->
yield @player.update({$set: {stripe: {free: true}}})
[res, body] = yield request.getAsync { uri: @url, json: true }
expect(res.statusCode).toBe(200)
done()

View file

@ -11,6 +11,7 @@ describe 'EnrollmentsView', ->
beforeEach (done) -> beforeEach (done) ->
me.set('anonymous', false) me.set('anonymous', false)
me.set('role', 'teacher') me.set('role', 'teacher')
me.set('enrollmentRequestSent', false)
@view = new EnrollmentsView() @view = new EnrollmentsView()
# Make three classrooms, sharing users from a pool of 10, 5 of which are enrolled # Make three classrooms, sharing users from a pool of 10, 5 of which are enrolled
@ -92,7 +93,8 @@ describe 'EnrollmentsView', ->
describe 'when there are no prepaids to show', -> describe 'when there are no prepaids to show', ->
beforeEach (done) -> beforeEach (done) ->
@view.prepaids.reset() @view.prepaids.reset([])
@view.updatePrepaidGroups()
_.defer(done) _.defer(done)
it 'fills the void with the rest of the page content', -> it 'fills the void with the rest of the page content', ->

View file

@ -45,9 +45,6 @@ describe 'TeachersContactModal', ->
it 'shows a success message', -> it 'shows a success message', ->
expect(@modal.$('.alert-success').length).toBe(1) expect(@modal.$('.alert-success').length).toBe(1)
describe 'submit button', -> it 'disables the submit button', ->
it 'is disabled until one of the inputs changes', ->
expect(@modal.$('#submit-btn').is(':disabled')).toBe(true) expect(@modal.$('#submit-btn').is(':disabled')).toBe(true)
@modal.$('input[name="email"]').trigger('change')
expect(@modal.$('#submit-btn').is(':disabled')).toBe(false)

View file

@ -12,7 +12,8 @@ describe 'EditStudentModal', ->
describe 'for a verified user', -> describe 'for a verified user', ->
beforeEach (done) -> beforeEach (done) ->
user = factories.makeUser({ email, emailVerified: true }) user = factories.makeUser({ email, emailVerified: true })
modal = new EditStudentModal({ user }) classroom = factories.makeClassroom()
modal = new EditStudentModal({ user, classroom })
request = jasmine.Ajax.requests.mostRecent() request = jasmine.Ajax.requests.mostRecent()
request.respondWith({ status: 200, responseText: JSON.stringify(user) }) request.respondWith({ status: 200, responseText: JSON.stringify(user) })
jasmine.demoModal(modal) jasmine.demoModal(modal)
@ -37,7 +38,8 @@ describe 'EditStudentModal', ->
describe 'for an unverified user', -> describe 'for an unverified user', ->
beforeEach (done) -> beforeEach (done) ->
user = factories.makeUser({ email , emailVerified: false }) user = factories.makeUser({ email , emailVerified: false })
modal = new EditStudentModal({ user }) classroom = factories.makeClassroom()
modal = new EditStudentModal({ user, classroom })
request = jasmine.Ajax.requests.mostRecent() request = jasmine.Ajax.requests.mostRecent()
request.respondWith({ status: 200, responseText: JSON.stringify(user) }) request.respondWith({ status: 200, responseText: JSON.stringify(user) })
jasmine.demoModal(modal) jasmine.demoModal(modal)