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
d3459be0
Commit
d3459be0
authored
Dec 17, 2014
by
Will Daly
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add Jasmine tests for the payment/verification flow.
parent
9bd1f3a8
Show whitespace changes
Inline
Side-by-side
Showing
27 changed files
with
1098 additions
and
98 deletions
+1098
-98
common/static/js/spec_helpers/ajax_helpers.js
+18
-1
lms/djangoapps/verify_student/views.py
+1
-1
lms/static/js/spec/main.js
+115
-2
lms/static/js/spec/photocapture_spec.js
+0
-0
lms/static/js/spec/verify_student/make_payment_step_view_spec.js
+249
-0
lms/static/js/spec/verify_student/pay_and_verify_view_spec.js
+188
-0
lms/static/js/spec/verify_student/review_photos_step_view_spec.js
+149
-0
lms/static/js/spec/verify_student/webcam_photo_view_spec.js
+212
-0
lms/static/js/verify_student/pay_and_verify.js
+6
-3
lms/static/js/verify_student/views/enrollment_confirmation_step_view.js
+8
-0
lms/static/js/verify_student/views/intro_step_view.js
+8
-0
lms/static/js/verify_student/views/make_payment_step_view.js
+46
-15
lms/static/js/verify_student/views/pay_and_verify_view.js
+2
-4
lms/static/js/verify_student/views/review_photos_step_view.js
+18
-13
lms/static/js/verify_student/views/step_view.js
+26
-14
lms/static/js/verify_student/views/webcam_photo_view.js
+30
-26
lms/static/js_test.yml
+1
-0
lms/templates/verify_student/enrollment_confirmation_step.underscore
+1
-1
lms/templates/verify_student/face_photo_step.underscore
+1
-1
lms/templates/verify_student/id_photo_step.underscore
+1
-1
lms/templates/verify_student/intro_step.underscore
+4
-4
lms/templates/verify_student/make_payment_step.underscore
+8
-6
lms/templates/verify_student/pay_and_verify.html
+1
-1
lms/templates/verify_student/payment_confirmation_step.underscore
+1
-1
lms/templates/verify_student/progress.underscore
+1
-1
lms/templates/verify_student/review_photos_step.underscore
+1
-1
lms/templates/verify_student/webcam_photo.underscore
+2
-2
No files found.
common/static/js/spec_helpers/ajax_helpers.js
View file @
d3459be0
define
([
'sinon'
,
'underscore'
],
function
(
sinon
,
_
)
{
var
fakeServer
,
fakeRequests
,
expectRequest
,
expectJsonRequest
,
respondWithJson
,
respondWithError
,
respondToDelete
;
respondWithJson
,
respondWithError
,
respond
WithTextError
,
respond
ToDelete
;
/* These utility methods are used by Jasmine tests to create a mock server or
* get reference to mock requests. In either case, the cleanup (restore) is done with
...
...
@@ -93,6 +93,22 @@ define(['sinon', 'underscore'], function(sinon, _) {
);
};
respondWithTextError
=
function
(
requests
,
statusCode
,
textResponse
,
requestIndex
)
{
if
(
_
.
isUndefined
(
requestIndex
))
{
requestIndex
=
requests
.
length
-
1
;
}
if
(
_
.
isUndefined
(
statusCode
))
{
statusCode
=
500
;
}
if
(
_
.
isUndefined
(
textResponse
))
{
textResponse
=
""
;
}
requests
[
requestIndex
].
respond
(
statusCode
,
{
'Content-Type'
:
'text/plain'
},
textResponse
);
};
respondToDelete
=
function
(
requests
,
requestIndex
)
{
if
(
_
.
isUndefined
(
requestIndex
))
{
requestIndex
=
requests
.
length
-
1
;
...
...
@@ -108,6 +124,7 @@ define(['sinon', 'underscore'], function(sinon, _) {
'expectJsonRequest'
:
expectJsonRequest
,
'respondWithJson'
:
respondWithJson
,
'respondWithError'
:
respondWithError
,
'respondWithTextError'
:
respondWithTextError
,
'respondToDelete'
:
respondToDelete
};
});
lms/djangoapps/verify_student/views.py
View file @
d3459be0
...
...
@@ -512,7 +512,7 @@ class PayAndVerifyView(View):
'disable_courseware_js'
:
True
,
'display_steps'
:
display_steps
,
'contribution_amount'
:
contribution_amount
,
'is_active'
:
request
.
user
.
is_active
,
'is_active'
:
json
.
dumps
(
request
.
user
.
is_active
)
,
'messages'
:
self
.
_messages
(
message
,
course
.
display_name
,
...
...
lms/static/js/spec/main.js
View file @
d3459be0
...
...
@@ -384,7 +384,116 @@
'js/student_account/enrollment'
,
'js/student_account/shoppingcart'
,
]
}
},
'js/verify_student/models/verification_model'
:
{
exports
:
'edx.verify_student.VerificationModel'
,
deps
:
[
'jquery'
,
'underscore'
,
'backbone'
,
'jquery.cookie'
]
},
'js/verify_student/views/error_view'
:
{
exports
:
'edx.verify_student.ErrorView'
,
deps
:
[
'jquery'
,
'underscore'
,
'backbone'
]
},
'js/verify_student/views/webcam_photo_view'
:
{
exports
:
'edx.verify_student.WebcamPhotoView'
,
deps
:
[
'jquery'
,
'underscore'
,
'backbone'
,
'gettext'
]
},
'js/verify_student/views/progress_view'
:
{
exports
:
'edx.verify_student.ProgressView'
,
deps
:
[
'jquery'
,
'underscore'
,
'backbone'
,
'gettext'
]
},
'js/verify_student/views/requirements_view'
:
{
exports
:
'edx.verify_student.RequirementsView'
,
deps
:
[
'jquery'
,
'backbone'
,
'underscore'
,
'gettext'
]
},
'js/verify_student/views/step_view'
:
{
exports
:
'edx.verify_student.StepView'
,
deps
:
[
'jquery'
,
'underscore'
,
'underscore.string'
,
'backbone'
,
'gettext'
]
},
'js/verify_student/views/intro_step_view'
:
{
exports
:
'edx.verify_student.IntroStepView'
,
deps
:
[
'jquery'
,
'js/verify_student/views/step_view'
,
'js/verify_student/views/requirements_view'
]
},
'js/verify_student/views/make_payment_step_view'
:
{
exports
:
'edx.verify_student.MakePaymentStepView'
,
deps
:
[
'jquery'
,
'underscore'
,
'gettext'
,
'jquery.cookie'
,
'jquery.url'
,
'js/verify_student/views/step_view'
,
'js/verify_student/views/requirements_view'
]
},
'js/verify_student/views/payment_confirmation_step_view'
:
{
exports
:
'edx.verify_student.PaymentConfirmationStepView'
,
deps
:
[
'jquery'
,
'underscore'
,
'gettext'
,
'js/verify_student/views/step_view'
,
'js/verify_student/views/requirements_view'
]
},
'js/verify_student/views/face_photo_step_view'
:
{
exports
:
'edx.verify_student.FacePhotoStepView'
,
deps
:
[
'jquery'
,
'underscore'
,
'gettext'
,
'js/verify_student/views/step_view'
,
'js/verify_student/views/webcam_photo_view'
]
},
'js/verify_student/views/id_photo_step_view'
:
{
exports
:
'edx.verify_student.IDPhotoStepView'
,
deps
:
[
'jquery'
,
'underscore'
,
'gettext'
,
'js/verify_student/views/step_view'
,
'js/verify_student/views/webcam_photo_view'
]
},
'js/verify_student/views/review_photos_step_view'
:
{
exports
:
'edx.verify_student.ReviewPhotosStepView'
,
deps
:
[
'jquery'
,
'underscore'
,
'gettext'
,
'js/verify_student/views/step_view'
,
'js/verify_student/views/webcam_photo_view'
]
},
'js/verify_student/views/enrollment_confirmation_step_view'
:
{
exports
:
'edx.verify_student.EnrollmentConfirmationStepView'
,
deps
:
[
'jquery'
,
'js/verify_student/views/step_view'
,
]
},
'js/verify_student/views/pay_and_verify_view'
:
{
exports
:
'edx.verify_student.PayAndVerifyView'
,
deps
:
[
'jquery'
,
'underscore'
,
'backbone'
,
'gettext'
,
'js/verify_student/models/verification_model'
,
'js/verify_student/views/progress_view'
,
'js/verify_student/views/intro_step_view'
,
'js/verify_student/views/make_payment_step_view'
,
'js/verify_student/views/payment_confirmation_step_view'
,
'js/verify_student/views/face_photo_step_view'
,
'js/verify_student/views/id_photo_step_view'
,
'js/verify_student/views/review_photos_step_view'
,
'js/verify_student/views/enrollment_confirmation_step_view'
]
},
}
});
...
...
@@ -406,7 +515,11 @@
'lms/include/js/spec/student_account/enrollment_spec.js'
,
'lms/include/js/spec/student_account/emailoptin_spec.js'
,
'lms/include/js/spec/student_account/shoppingcart_spec.js'
,
'lms/include/js/spec/student_profile/profile_spec.js'
'lms/include/js/spec/student_profile/profile_spec.js'
,
'lms/include/js/spec/verify_student/pay_and_verify_view_spec.js'
,
'lms/include/js/spec/verify_student/webcam_photo_view_spec.js'
,
'lms/include/js/spec/verify_student/review_photos_step_view_spec.js'
,
'lms/include/js/spec/verify_student/make_payment_step_view_spec.js'
]);
}).
call
(
this
,
requirejs
,
define
);
lms/static/js/spec/photocapture_spec.js
View file @
d3459be0
lms/static/js/spec/verify_student/make_payment_step_view_spec.js
0 → 100644
View file @
d3459be0
define
([
'jquery'
,
'underscore'
,
'backbone'
,
'js/common_helpers/ajax_helpers'
,
'js/common_helpers/template_helpers'
,
'js/verify_student/views/make_payment_step_view'
],
function
(
$
,
_
,
Backbone
,
AjaxHelpers
,
TemplateHelpers
,
MakePaymentStepView
)
{
'use strict'
;
describe
(
'edx.verify_student.MakePaymentStepView'
,
function
()
{
var
PAYMENT_URL
=
"/pay"
;
var
PAYMENT_PARAMS
=
{
orderId
:
"test-order"
,
signature
:
"abcd1234"
};
var
STEP_DATA
=
{
minPrice
:
"12"
,
suggestedPrices
:
[
"34.56"
,
"78.90"
],
currency
:
"usd"
,
purchaseEndpoint
:
PAYMENT_URL
,
courseKey
:
"edx/test/test"
};
var
SERVER_ERROR_MSG
=
"An error occurred!"
;
var
createView
=
function
(
stepDataOverrides
)
{
var
view
=
new
MakePaymentStepView
({
el
:
$
(
'#current-step-container'
),
templateName
:
'make_payment_step'
,
stepData
:
_
.
extend
(
_
.
clone
(
STEP_DATA
),
stepDataOverrides
),
errorModel
:
new
(
Backbone
.
Model
.
extend
({})
)()
}).
render
();
// Stub the payment form submission
spyOn
(
view
,
'submitForm'
).
andCallFake
(
function
()
{}
);
return
view
;
};
var
expectPriceOptions
=
function
(
prices
)
{
var
sel
;
_
.
each
(
prices
,
function
(
price
)
{
sel
=
_
.
sprintf
(
'input[name="contribution"][value="%s"]'
,
price
);
expect
(
$
(
sel
).
length
>
0
).
toBe
(
true
);
});
};
var
expectPriceSelected
=
function
(
price
)
{
var
sel
=
$
(
_
.
sprintf
(
'input[name="contribution"][value="%s"]'
,
price
)
);
// If the option is available, it should be selected
if
(
sel
.
length
>
0
)
{
expect
(
sel
.
prop
(
'checked'
)
).
toBe
(
true
);
}
else
{
// Otherwise, the text box amount should be filled in
expect
(
$
(
'#contribution-other'
).
prop
(
'checked'
)
).
toBe
(
true
);
expect
(
$
(
'#contribution-other-amt'
).
val
()
).
toEqual
(
price
);
}
};
var
choosePriceOption
=
function
(
price
)
{
var
sel
=
_
.
sprintf
(
'input[name="contribution"][value="%s"]'
,
price
);
$
(
sel
).
trigger
(
'click'
);
};
var
enterPrice
=
function
(
price
)
{
$
(
'#contribution-other'
).
trigger
(
'click'
);
$
(
'#contribution-other-amt'
).
val
(
price
);
};
var
expectSinglePriceDisplayed
=
function
(
price
)
{
var
displayedPrice
=
$
(
'.contribution-option .label-value'
).
text
();
expect
(
displayedPrice
).
toEqual
(
price
);
};
var
expectPaymentButtonEnabled
=
function
(
isEnabled
)
{
var
isDisabled
=
$
(
'#pay_button'
).
hasClass
(
'is-disabled'
);
expect
(
!
isDisabled
).
toEqual
(
isEnabled
);
};
var
expectPaymentDisabledBecauseInactive
=
function
()
{
var
payButton
=
$
(
'#pay_button'
),
activateButton
=
$
(
'#activate_button'
);
// Payment button should be hidden
expect
(
payButton
.
length
).
toEqual
(
0
);
// Activate button should be displayed and disabled
expect
(
activateButton
.
length
).
toEqual
(
1
);
expect
(
activateButton
.
hasClass
(
'is-disabled'
)
).
toBe
(
true
);
};
var
goToPayment
=
function
(
requests
,
kwargs
)
{
var
params
=
{
contribution
:
kwargs
.
amount
||
""
,
course_id
:
kwargs
.
courseId
||
""
};
// Click the "go to payment" button
$
(
'#pay_button'
).
click
();
// Verify that the request was made to the server
AjaxHelpers
.
expectRequest
(
requests
,
"POST"
,
"/verify_student/create_order/"
,
$
.
param
(
params
)
);
// Simulate the server response
if
(
kwargs
.
succeeds
)
{
AjaxHelpers
.
respondWithJson
(
requests
,
PAYMENT_PARAMS
);
}
else
{
AjaxHelpers
.
respondWithTextError
(
requests
,
400
,
SERVER_ERROR_MSG
);
}
};
var
expectPaymentSubmitted
=
function
(
view
,
params
)
{
var
form
;
expect
(
view
.
submitForm
).
toHaveBeenCalled
();
form
=
view
.
submitForm
.
mostRecentCall
.
args
[
0
];
expect
(
form
.
serialize
()).
toEqual
(
$
.
param
(
params
));
expect
(
form
.
attr
(
'method'
)).
toEqual
(
"POST"
);
expect
(
form
.
attr
(
'action'
)).
toEqual
(
PAYMENT_URL
);
};
var
expectErrorDisplayed
=
function
(
errorTitle
)
{
var
actualTitle
=
$
(
'#error h3.title'
).
text
();
expect
(
actualTitle
).
toEqual
(
errorTitle
);
};
beforeEach
(
function
()
{
window
.
analytics
=
jasmine
.
createSpyObj
(
'analytics'
,
[
'track'
,
'page'
,
'trackLink'
]);
setFixtures
(
'<div id="current-step-container"></div>'
);
TemplateHelpers
.
installTemplate
(
'templates/verify_student/make_payment_step'
);
TemplateHelpers
.
installTemplate
(
'templates/verify_student/requirements'
);
});
it
(
'allows users to choose a suggested price'
,
function
()
{
var
view
=
createView
({}),
requests
=
AjaxHelpers
.
requests
(
this
);
expectPriceOptions
(
STEP_DATA
.
suggestedPrices
);
expectPaymentButtonEnabled
(
false
);
choosePriceOption
(
STEP_DATA
.
suggestedPrices
[
1
]
);
expectPaymentButtonEnabled
(
true
);
goToPayment
(
requests
,
{
amount
:
STEP_DATA
.
suggestedPrices
[
1
],
courseId
:
STEP_DATA
.
courseKey
,
succeeds
:
true
});
expectPaymentSubmitted
(
view
,
PAYMENT_PARAMS
);
});
it
(
'allows users to pay the minimum price if no suggested prices are given'
,
function
()
{
var
view
=
createView
({
suggestedPrices
:
[]
}),
requests
=
AjaxHelpers
.
requests
(
this
);
expectSinglePriceDisplayed
(
STEP_DATA
.
minPrice
);
expectPaymentButtonEnabled
(
true
);
goToPayment
(
requests
,
{
amount
:
STEP_DATA
.
minPrice
,
courseId
:
STEP_DATA
.
courseKey
,
succeeds
:
true
});
expectPaymentSubmitted
(
view
,
PAYMENT_PARAMS
);
});
it
(
'allows the user to enter a contribution amount'
,
function
()
{
var
view
=
createView
({}),
requests
=
AjaxHelpers
.
requests
(
this
);
enterPrice
(
"67.89"
);
expectPaymentButtonEnabled
(
true
);
goToPayment
(
requests
,
{
amount
:
"67.89"
,
courseId
:
STEP_DATA
.
courseKey
,
succeeds
:
true
});
expectPaymentSubmitted
(
view
,
PAYMENT_PARAMS
);
});
it
(
'selects in the contribution amount if provided'
,
function
()
{
// Pre-select one of the suggested prices
createView
({
contributionAmount
:
STEP_DATA
.
suggestedPrices
[
1
]
});
// Expect that the price is selected
expectPriceSelected
(
STEP_DATA
.
suggestedPrices
[
1
]);
});
it
(
'fills in the contribution amount if provided'
,
function
()
{
// Pre-select a price NOT in the suggestions
createView
({
contributionAmount
:
'99.99'
});
// Expect that the price is filled in
expectPriceSelected
(
'99.99'
);
});
it
(
'ignores the contribution pre-selected if no suggested prices are given'
,
function
()
{
// No suggested prices, but a contribution is set
createView
({
suggestedPrices
:
[],
contributionAmount
:
'99.99'
});
// Expect that the single price is displayed
expectSinglePriceDisplayed
(
STEP_DATA
.
minPrice
);
});
it
(
'disables payment for inactive users'
,
function
()
{
createView
({
isActive
:
false
});
expectPaymentDisabledBecauseInactive
();
});
it
(
'displays an error if the order could not be created'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
),
view
=
createView
({});
choosePriceOption
(
STEP_DATA
.
suggestedPrices
[
0
]
);
goToPayment
(
requests
,
{
amount
:
STEP_DATA
.
suggestedPrices
[
0
],
courseId
:
STEP_DATA
.
courseKey
,
succeeds
:
false
});
// Expect that an error is displayed
expect
(
view
.
errorModel
.
get
(
'shown'
)
).
toBe
(
true
);
expect
(
view
.
errorModel
.
get
(
'errorTitle'
)
).
toEqual
(
'Could not submit order'
);
expect
(
view
.
errorModel
.
get
(
'errorMsg'
)
).
toEqual
(
SERVER_ERROR_MSG
);
// Expect that the payment button is re-enabled
expectPaymentButtonEnabled
(
true
);
});
});
}
);
lms/static/js/spec/verify_student/pay_and_verify_view_spec.js
0 → 100644
View file @
d3459be0
define
([
'jquery'
,
'js/common_helpers/template_helpers'
,
'js/verify_student/views/pay_and_verify_view'
],
function
(
$
,
TemplateHelpers
,
PayAndVerifyView
)
{
'use strict'
;
describe
(
'edx.verify_student.PayAndVerifyView'
,
function
()
{
var
TEMPLATES
=
[
'enrollment_confirmation_step'
,
'error'
,
'face_photo_step'
,
'id_photo_step'
,
'intro_step'
,
'make_payment_step'
,
'payment_confirmation_step'
,
'progress'
,
'requirements'
,
'review_photos_step'
,
'webcam_photo'
];
var
INTRO_STEP
=
{
templateName
:
"intro_step"
,
name
:
"intro-step"
,
title
:
"Intro"
};
var
DISPLAY_STEPS_FOR_PAYMENT
=
[
{
templateName
:
"make_payment_step"
,
name
:
"make-payment-step"
,
title
:
"Make Payment"
},
{
templateName
:
"payment_confirmation_step"
,
name
:
"payment-confirmation-step"
,
title
:
"Payment Confirmation"
}
];
var
DISPLAY_STEPS_FOR_VERIFICATION
=
[
{
templateName
:
"face_photo_step"
,
name
:
"face-photo-step"
,
title
:
"Take Face Photo"
},
{
templateName
:
"id_photo_step"
,
name
:
"id-photo-step"
,
title
:
"ID Photo"
},
{
templateName
:
"review_photos_step"
,
name
:
"review-photos-step"
,
title
:
"Review Photos"
},
{
templateName
:
"enrollment_confirmation_step"
,
name
:
"enrollment-confirmation-step"
,
title
:
"Enrollment Confirmation"
}
];
var
createView
=
function
(
displaySteps
,
currentStep
)
{
return
new
PayAndVerifyView
({
displaySteps
:
displaySteps
,
currentStep
:
currentStep
}).
render
();
};
var
expectStepRendered
=
function
(
stepName
,
stepNum
,
numSteps
)
{
var
i
,
j
,
sel
;
// Expect that the step container div rendered
expect
(
$
(
'.'
+
stepName
).
length
>
0
).
toBe
(
true
);
// Expect that the progress indicator shows the correct step
expect
(
$
(
'#progress-step-'
+
stepNum
).
hasClass
(
'is-current'
)
).
toBe
(
true
);
// Expect that all steps before this step are completed
for
(
i
=
1
;
i
<
stepNum
;
i
++
)
{
sel
=
$
(
'#progress-step-'
+
i
);
expect
(
sel
.
hasClass
(
'is-completed'
)
).
toBe
(
true
);
expect
(
sel
.
hasClass
(
'is-current'
)
).
toBe
(
false
);
}
// Expect that all steps after this step are neither completed nor current
for
(
j
=
stepNum
+
1
;
j
<=
numSteps
;
j
++
)
{
sel
=
$
(
'#progress-step-'
+
j
);
expect
(
sel
.
hasClass
(
'is-completed'
)
).
toBe
(
false
);
expect
(
sel
.
hasClass
(
'is-current'
)
).
toBe
(
false
);
}
};
beforeEach
(
function
()
{
window
.
analytics
=
jasmine
.
createSpyObj
(
'analytics'
,
[
'track'
,
'page'
,
'trackLink'
]);
setFixtures
(
'<div id="pay-and-verify-container"></div>'
);
$
.
each
(
TEMPLATES
,
function
(
index
,
templateName
)
{
TemplateHelpers
.
installTemplate
(
'templates/verify_student/'
+
templateName
);
});
});
it
(
'renders payment and verification steps'
,
function
()
{
// Create the view, starting on the first step
var
view
=
createView
(
DISPLAY_STEPS_FOR_PAYMENT
.
concat
(
DISPLAY_STEPS_FOR_VERIFICATION
),
'make-payment-step'
);
// Verify that the first step rendered
expectStepRendered
(
'make-payment-step'
,
1
,
6
);
// Iterate through the steps, ensuring that each is rendered
view
.
nextStep
();
expectStepRendered
(
'payment-confirmation-step'
,
2
,
6
);
view
.
nextStep
();
expectStepRendered
(
'face-photo-step'
,
3
,
6
);
view
.
nextStep
();
expectStepRendered
(
'id-photo-step'
,
4
,
6
);
view
.
nextStep
();
expectStepRendered
(
'review-photos-step'
,
5
,
6
);
view
.
nextStep
();
expectStepRendered
(
'enrollment-confirmation-step'
,
6
,
6
);
// Going past the last step stays on the last step
view
.
nextStep
();
expectStepRendered
(
'enrollment-confirmation-step'
,
6
,
6
);
});
it
(
'renders intro and verification steps'
,
function
()
{
var
view
=
createView
(
[
INTRO_STEP
].
concat
(
DISPLAY_STEPS_FOR_VERIFICATION
),
'intro-step'
);
// Verify that the first step rendered
expectStepRendered
(
'intro-step'
,
1
,
5
);
// Iterate through the steps, ensuring that each is rendered
view
.
nextStep
();
expectStepRendered
(
'face-photo-step'
,
2
,
5
);
view
.
nextStep
();
expectStepRendered
(
'id-photo-step'
,
3
,
5
);
view
.
nextStep
();
expectStepRendered
(
'review-photos-step'
,
4
,
5
);
view
.
nextStep
();
expectStepRendered
(
'enrollment-confirmation-step'
,
5
,
5
);
});
it
(
'starts from a later step'
,
function
()
{
// Start from the payment confirmation step
var
view
=
createView
(
DISPLAY_STEPS_FOR_PAYMENT
.
concat
(
DISPLAY_STEPS_FOR_VERIFICATION
),
'payment-confirmation-step'
);
// Verify that we start on the right step
expectStepRendered
(
'payment-confirmation-step'
,
2
,
6
);
// Try moving to the next step
view
.
nextStep
();
expectStepRendered
(
'face-photo-step'
,
3
,
6
);
});
it
(
'jumps to a particular step'
,
function
()
{
// Start on the review photos step
var
view
=
createView
(
DISPLAY_STEPS_FOR_VERIFICATION
,
'review-photos-step'
);
// Jump back to the face photo step
view
.
goToStep
(
'face-photo-step'
);
expectStepRendered
(
'face-photo-step'
,
1
,
4
);
});
});
}
);
lms/static/js/spec/verify_student/review_photos_step_view_spec.js
0 → 100644
View file @
d3459be0
define
([
'jquery'
,
'underscore'
,
'backbone'
,
'js/common_helpers/ajax_helpers'
,
'js/common_helpers/template_helpers'
,
'js/verify_student/views/review_photos_step_view'
,
'js/verify_student/models/verification_model'
],
function
(
$
,
_
,
Backbone
,
AjaxHelpers
,
TemplateHelpers
,
ReviewPhotosStepView
,
VerificationModel
)
{
'use strict'
;
describe
(
'edx.verify_student.ReviewPhotosStepView'
,
function
()
{
var
STEP_DATA
=
{},
FULL_NAME
=
"Test User"
,
FACE_IMAGE
=
"abcd1234"
,
PHOTO_ID_IMAGE
=
"efgh56789"
,
SERVER_ERROR_MSG
=
"An error occurred!"
;
var
createView
=
function
()
{
return
new
ReviewPhotosStepView
({
el
:
$
(
'#current-step-container'
),
templateName
:
'review_photos_step'
,
stepData
:
STEP_DATA
,
model
:
new
VerificationModel
({
faceImage
:
FACE_IMAGE
,
identificationImage
:
PHOTO_ID_IMAGE
}),
errorModel
:
new
(
Backbone
.
Model
.
extend
({})
)()
}).
render
();
};
var
confirmPhotos
=
function
(
isConfirmed
)
{
$
(
'#confirm_pics_good'
).
trigger
(
'click'
);
};
var
submitPhotos
=
function
(
requests
,
expectedParams
,
succeeds
)
{
// Submit the photos
$
(
'#next_step_button'
).
click
();
// Expect a request to the server
AjaxHelpers
.
expectRequest
(
requests
,
"POST"
,
"/verify_student/submit-photos/"
,
$
.
param
(
expectedParams
)
);
// Simulate the server response
if
(
succeeds
)
{
AjaxHelpers
.
respondWithJson
(
requests
);
}
else
{
AjaxHelpers
.
respondWithTextError
(
requests
,
400
,
SERVER_ERROR_MSG
);
}
};
var
setFullName
=
function
(
fullName
)
{
$
(
'#new-name'
).
val
(
fullName
);
};
var
expectSubmitEnabled
=
function
(
isEnabled
)
{
var
isDisabled
=
$
(
'#next_step_button'
).
hasClass
(
'is-disabled'
);
expect
(
!
isDisabled
).
toBe
(
isEnabled
);
};
beforeEach
(
function
()
{
window
.
analytics
=
jasmine
.
createSpyObj
(
'analytics'
,
[
'track'
,
'page'
,
'trackLink'
]);
setFixtures
(
'<div id="current-step-container"></div>'
);
TemplateHelpers
.
installTemplate
(
'templates/verify_student/review_photos_step'
);
});
it
(
'requires the user to confirm before submitting photos'
,
function
()
{
createView
();
// Initially disabled
expectSubmitEnabled
(
false
);
// Confirm the photos, enabling submission
confirmPhotos
(
true
);
expectSubmitEnabled
(
true
);
// Unconfirm the photos, disabling submission
confirmPhotos
(
false
);
expectSubmitEnabled
(
false
);
});
it
(
'allows the user to change her full name'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
createView
();
setFullName
(
FULL_NAME
);
confirmPhotos
(
true
);
submitPhotos
(
requests
,
{
face_image
:
FACE_IMAGE
,
photo_id_image
:
PHOTO_ID_IMAGE
,
full_name
:
FULL_NAME
},
true
);
});
it
(
'submits photos for verification'
,
function
()
{
var
requests
=
AjaxHelpers
.
requests
(
this
);
createView
();
confirmPhotos
(
true
);
submitPhotos
(
requests
,
{
face_image
:
FACE_IMAGE
,
photo_id_image
:
PHOTO_ID_IMAGE
},
true
);
// Expect that submission is disabled to prevent
// duplicate submission.
expectSubmitEnabled
(
false
);
});
it
(
'displays an error if photo submission fails'
,
function
()
{
var
view
=
createView
(),
requests
=
AjaxHelpers
.
requests
(
this
);
confirmPhotos
(
true
);
submitPhotos
(
requests
,
{
face_image
:
FACE_IMAGE
,
photo_id_image
:
PHOTO_ID_IMAGE
},
false
);
// Expect the submit button is re-enabled to allow
// the user to retry.
expectSubmitEnabled
(
true
);
// Expect that an error message is displayed
expect
(
view
.
errorModel
.
get
(
'shown'
)
).
toBe
(
true
);
expect
(
view
.
errorModel
.
get
(
'errorTitle'
)
).
toEqual
(
'Could not submit photos'
);
expect
(
view
.
errorModel
.
get
(
'errorMsg'
)
).
toEqual
(
SERVER_ERROR_MSG
);
});
});
}
);
lms/static/js/spec/verify_student/webcam_photo_view_spec.js
0 → 100644
View file @
d3459be0
define
([
'jquery'
,
'backbone'
,
'js/common_helpers/template_helpers'
,
'js/common_helpers/ajax_helpers'
,
'js/verify_student/views/webcam_photo_view'
,
'js/verify_student/models/verification_model'
],
function
(
$
,
Backbone
,
TemplateHelpers
,
AjaxHelpers
,
WebcamPhotoView
,
VerificationModel
)
{
'use strict'
;
describe
(
'edx.verify_student.WebcamPhotoView'
,
function
()
{
var
IMAGE_DATA
=
"abcd1234"
,
VIDEO_ERROR_TITLE
=
"video capture error"
,
VIDEO_ERROR_MSG
=
"video error msg"
;
/**
* For the purposes of these tests, we stub out the backend
* video capture implementation.
* This allows us to easily test the application logic
* without needing to handle the subtleties of video capture
* (especially cross-browser).
* However, this means that the test suite does NOT adequately
* cover the HTML5 / Flash webcam integration. We will need
* cross-browser manual testing to verify that this works correctly.
*/
var
StubBackend
=
function
(
name
,
isSupported
,
snapshotSuccess
)
{
if
(
_
.
isUndefined
(
isSupported
)
)
{
isSupported
=
true
;
}
if
(
_
.
isUndefined
(
snapshotSuccess
)
)
{
snapshotSuccess
=
true
;
}
return
{
name
:
name
,
initialize
:
function
()
{},
isSupported
:
function
()
{
return
isSupported
;
},
snapshot
:
function
()
{
return
snapshotSuccess
;
},
getImageData
:
function
()
{
return
IMAGE_DATA
;
},
reset
:
function
()
{}
};
};
var
createView
=
function
(
backends
)
{
return
new
WebcamPhotoView
({
el
:
$
(
'#current-step-container'
),
model
:
new
VerificationModel
({}),
modelAttribute
:
'faceImage'
,
errorModel
:
new
(
Backbone
.
Model
.
extend
({})
)(),
submitButton
:
$
(
'#submit_button'
),
backends
:
backends
}).
render
();
};
var
takeSnapshot
=
function
()
{
$
(
'#webcam_capture_button'
).
click
();
};
var
resetWebcam
=
function
()
{
$
(
'#webcam_reset_button'
).
click
();
};
var
expectButtonShown
=
function
(
obj
)
{
var
resetButton
=
$
(
'#webcam_reset_button'
),
captureButton
=
$
(
'#webcam_capture_button'
);
expect
(
captureButton
.
hasClass
(
'is-hidden'
)
).
toBe
(
!
obj
.
snapshot
);
expect
(
resetButton
.
hasClass
(
'is-hidden'
)
).
toBe
(
!
obj
.
reset
);
};
var
expectSubmitEnabled
=
function
(
isEnabled
)
{
var
isDisabled
=
$
(
'#submit_button'
).
hasClass
(
'is-disabled'
);
expect
(
!
isDisabled
).
toEqual
(
isEnabled
);
};
beforeEach
(
function
()
{
window
.
analytics
=
jasmine
.
createSpyObj
(
'analytics'
,
[
'track'
,
'page'
,
'trackLink'
]);
setFixtures
(
'<div id="current-step-container"></div>'
+
'<input type="button" id="submit_button" class="is-disabled"></input>'
);
TemplateHelpers
.
installTemplate
(
'templates/verify_student/webcam_photo'
);
});
it
(
'takes a snapshot'
,
function
()
{
var
view
=
createView
(
[
StubBackend
(
"html5"
)
]
);
// Spy on the backend
spyOn
(
view
.
backend
,
'snapshot'
).
andCallThrough
();
// Initially, only the snapshot button is shown
expectButtonShown
({
snapshot
:
true
,
reset
:
false
});
expectSubmitEnabled
(
false
);
// Take the snapshot
takeSnapshot
();
// Expect that the backend was used to take the snapshot
expect
(
view
.
backend
.
snapshot
).
toHaveBeenCalled
();
// Expect that buttons were updated
expectButtonShown
({
snapshot
:
false
,
reset
:
true
});
expectSubmitEnabled
(
true
);
// Expect that the image data was saved to the model
expect
(
view
.
model
.
get
(
'faceImage'
)
).
toEqual
(
IMAGE_DATA
);
});
it
(
'resets the camera'
,
function
()
{
var
view
=
createView
(
[
StubBackend
(
"html5"
)
]);
// Spy on the backend
spyOn
(
view
.
backend
,
'reset'
).
andCallThrough
();
// Take the snapshot, then reset
takeSnapshot
();
resetWebcam
();
// Expect that the backend was reset
expect
(
view
.
backend
.
reset
).
toHaveBeenCalled
();
// Expect that we're back to the initial button shown state
expectButtonShown
({
snapshot
:
true
,
reset
:
false
});
expectSubmitEnabled
(
false
);
// Expect that the image data is wiped from the model
expect
(
view
.
model
.
get
(
'faceImage'
)
).
toEqual
(
""
);
});
it
(
'falls back to a second video capture backend'
,
function
()
{
var
backends
=
[
StubBackend
(
"html5"
,
false
),
StubBackend
(
"flash"
,
true
)
],
view
=
createView
(
backends
);
// Expect that the second backend is chosen
expect
(
view
.
backend
.
name
).
toEqual
(
backends
[
1
].
name
);
});
it
(
'displays an error if no video backend is supported'
,
function
()
{
var
backends
=
[
StubBackend
(
"html5"
,
false
),
StubBackend
(
"flash"
,
false
)
],
view
=
createView
(
backends
);
// Expect an error
expect
(
view
.
errorModel
.
get
(
'errorTitle'
)
).
toEqual
(
'No Flash Detected'
);
expect
(
view
.
errorModel
.
get
(
'errorMsg'
)
).
toContain
(
'Get Flash'
);
expect
(
view
.
errorModel
.
get
(
'shown'
)
).
toBe
(
true
);
// Expect that submission is disabled
expectSubmitEnabled
(
false
);
});
it
(
'displays an error if the snapshot fails'
,
function
()
{
var
backends
=
[
StubBackend
(
"html5"
,
true
,
false
)
],
view
=
createView
(
backends
);
// Take a snapshot
takeSnapshot
();
// Do NOT expect an error displayed
expect
(
view
.
errorModel
.
get
(
'shown'
)
).
not
.
toBe
(
true
);
// Expect that the capture button is still enabled
// so the user can retry.
expectButtonShown
({
snapshot
:
true
,
reset
:
false
});
// Expect that submit is NOT enabled, since the user didn't
// successfully take a snapshot.
expectSubmitEnabled
(
false
);
});
it
(
'displays an error triggered by the backend'
,
function
()
{
var
view
=
createView
(
[
StubBackend
(
"html5"
)
]
);
// Simulate an error triggered by the backend
// This could occur at any point, including
// while the video capture is being set up.
view
.
backend
.
trigger
(
'error'
,
VIDEO_ERROR_TITLE
,
VIDEO_ERROR_MSG
);
// Verify that the error is displayed
expect
(
view
.
errorModel
.
get
(
'errorTitle'
)
).
toEqual
(
VIDEO_ERROR_TITLE
);
expect
(
view
.
errorModel
.
get
(
'errorMsg'
)
).
toEqual
(
VIDEO_ERROR_MSG
);
expect
(
view
.
errorModel
.
get
(
'shown'
)
).
toBe
(
true
);
// Expect that buttons are hidden
expectButtonShown
({
snapshot
:
false
,
reset
:
false
});
expectSubmitEnabled
(
false
);
});
});
}
);
lms/static/js/verify_student/pay_and_verify.js
View file @
d3459be0
...
...
@@ -10,7 +10,7 @@
*/
var
edx
=
edx
||
{};
(
function
(
$
)
{
(
function
(
$
,
_
)
{
'use strict'
;
var
errorView
,
el
=
$
(
'#pay-and-verify-container'
);
...
...
@@ -47,8 +47,11 @@ var edx = edx || {};
requirements
:
el
.
data
(
'requirements'
),
courseKey
:
el
.
data
(
'course-key'
),
minPrice
:
el
.
data
(
'course-mode-min-price'
),
suggestedPrices
:
(
el
.
data
(
'course-mode-suggested-prices'
)
||
""
).
split
(
","
),
contributionAmount
:
el
.
data
(
'contribution-amount'
),
suggestedPrices
:
_
.
filter
(
(
el
.
data
(
'course-mode-suggested-prices'
)
||
""
).
split
(
","
),
function
(
price
)
{
return
Boolean
(
price
);
}
),
currency
:
el
.
data
(
'course-mode-currency'
),
purchaseEndpoint
:
el
.
data
(
'purchase-endpoint'
)
},
...
...
@@ -68,4 +71,4 @@ var edx = edx || {};
}
}
}).
render
();
})(
jQuery
);
})(
jQuery
,
_
);
lms/static/js/verify_student/views/enrollment_confirmation_step_view.js
View file @
d3459be0
...
...
@@ -15,6 +15,14 @@ var edx = edx || {};
postRender
:
function
()
{
// Track a virtual pageview, for easy funnel reconstruction.
window
.
analytics
.
page
(
'verification'
,
this
.
templateName
);
},
defaultContext
:
function
()
{
return
{
courseName
:
''
,
courseStartDate
:
''
,
coursewareUrl
:
''
};
}
});
...
...
lms/static/js/verify_student/views/intro_step_view.js
View file @
d3459be0
...
...
@@ -10,6 +10,14 @@ var edx = edx || {};
edx
.
verify_student
.
IntroStepView
=
edx
.
verify_student
.
StepView
.
extend
({
defaultContext
:
function
()
{
return
{
introTitle
:
''
,
introMsg
:
''
,
isActive
:
false
};
},
// Currently, this view doesn't need to install any custom event handlers,
// since the button in the template reloads the page with a
// ?skip-intro=1 GET parameter. The reason for this is that we
...
...
lms/static/js/verify_student/views/make_payment_step_view.js
View file @
d3459be0
...
...
@@ -10,6 +10,15 @@ var edx = edx || {};
edx
.
verify_student
.
MakePaymentStepView
=
edx
.
verify_student
.
StepView
.
extend
({
defaultContext
:
function
()
{
return
{
isActive
:
true
,
suggestedPrices
:
[],
minPrice
:
0
,
currency
:
"usd"
};
},
postRender
:
function
()
{
// Render requirements
new
edx
.
verify_student
.
RequirementsView
({
...
...
@@ -26,8 +35,14 @@ var edx = edx || {};
this
.
selectPaymentAmount
(
this
.
stepData
.
contributionAmount
);
}
if
(
this
.
templateContext
().
suggestedPrices
.
length
>
0
)
{
// Enable the payment button once an amount is chosen
$
(
"input[name='contribution']"
).
on
(
'click'
,
_
.
bind
(
this
.
enablePaymentButton
,
this
)
);
}
else
{
// If there is only one payment option, then the user isn't shown
// radio buttons, so we need to enable the radio button.
this
.
enablePaymentButton
();
}
// Handle payment submission
$
(
"#pay_button"
).
on
(
'click'
,
_
.
bind
(
this
.
createOrder
,
this
)
);
...
...
@@ -89,41 +104,49 @@ var edx = edx || {};
// this page. A virtual pageview can be used to do this.
window
.
analytics
.
page
(
'payment'
,
'payment_processor_step'
);
form
.
submit
(
);
this
.
submitForm
(
form
);
},
handleCreateOrderError
:
function
(
xhr
)
{
var
errorMsg
=
gettext
(
'An unexpected error occurred. Please try again.'
);
if
(
xhr
.
status
===
400
)
{
errorMsg
=
xhr
.
responseText
;
}
this
.
errorModel
.
set
({
errorTitle
:
gettext
(
'Could not submit order'
),
errorMsg
:
xhr
.
responseText
,
shown
:
true
});
}
else
{
this
.
errorModel
.
set
({
errorTitle
:
gettext
(
'Could not submit order'
),
errorMsg
:
gettext
(
'An unexpected error occurred. Please try again'
),
errorMsg
:
errorMsg
,
shown
:
true
});
}
// Re-enable the button so the user can re-try
$
(
"#pay
ment-processor-form
"
).
removeClass
(
"is-disabled"
);
$
(
"#pay
_button
"
).
removeClass
(
"is-disabled"
);
},
getPaymentAmount
:
function
()
{
var
contributionInput
=
$
(
"input[name='contribution']:checked"
,
this
.
el
);
var
contributionInput
=
$
(
"input[name='contribution']:checked"
,
this
.
el
),
amount
=
null
;
if
(
contributionInput
.
attr
(
'id'
)
===
'contribution-other'
)
{
return
$
(
"input[name='contribution-other-amt']"
,
this
.
el
).
val
();
amount
=
$
(
"input[name='contribution-other-amt']"
,
this
.
el
).
val
();
}
else
{
return
contributionInput
.
val
();
amount
=
contributionInput
.
val
();
}
// If no suggested prices are available, then the user does not
// get the option to select a price. Default to the minimum.
if
(
!
amount
)
{
amount
=
this
.
templateContext
().
minPrice
;
}
return
amount
;
},
selectPaymentAmount
:
function
(
amount
)
{
var
amountFloat
=
parseFloat
(
amount
),
foundPrice
;
foundPrice
,
sel
;
// Check if we have a suggested price that matches the amount
foundPrice
=
_
.
find
(
...
...
@@ -135,7 +158,8 @@ var edx = edx || {};
// If we've found an option for the price, select it.
if
(
foundPrice
)
{
$
(
'#contribution-'
+
foundPrice
,
this
.
el
).
prop
(
'checked'
,
true
);
sel
=
_
.
sprintf
(
'input[name="contribution"][value="%s"]'
,
foundPrice
);
$
(
sel
).
prop
(
'checked'
,
true
);
}
else
{
// Otherwise, enter the value into the text box
$
(
'#contribution-other-amt'
,
this
.
el
).
val
(
amount
);
...
...
@@ -144,6 +168,13 @@ var edx = edx || {};
// In either case, enable the payment button
this
.
enablePaymentButton
();
return
amount
;
},
// Stubbed out in tests
submitForm
:
function
(
form
)
{
form
.
submit
();
}
});
...
...
lms/static/js/verify_student/views/pay_and_verify_view.js
View file @
d3459be0
...
...
@@ -16,8 +16,6 @@ var edx = edx || {};
edx
.
verify_student
.
PayAndVerifyView
=
Backbone
.
View
.
extend
({
el
:
'#pay-and-verify-container'
,
template
:
'#progress-tpl'
,
subviews
:
{},
VERIFICATION_VIEW_NAMES
:
[
...
...
@@ -27,7 +25,7 @@ var edx = edx || {};
],
initialize
:
function
(
obj
)
{
this
.
errorModel
=
obj
.
errorModel
||
{}
;
this
.
errorModel
=
obj
.
errorModel
||
null
;
this
.
displaySteps
=
obj
.
displaySteps
||
[];
this
.
progressView
=
new
edx
.
verify_student
.
ProgressView
({
...
...
@@ -43,7 +41,7 @@ var edx = edx || {};
)
});
this
.
initializeStepViews
(
obj
.
stepInfo
);
this
.
initializeStepViews
(
obj
.
stepInfo
||
{}
);
},
initializeStepViews
:
function
(
stepInfo
)
{
...
...
lms/static/js/verify_student/views/review_photos_step_view.js
View file @
d3459be0
...
...
@@ -10,9 +10,14 @@ var edx = edx || {};
edx
.
verify_student
.
ReviewPhotosStepView
=
edx
.
verify_student
.
StepView
.
extend
({
postRender
:
function
()
{
var
model
=
this
.
model
;
defaultContext
:
function
()
{
return
{
platformName
:
""
,
fullName
:
""
,
};
},
postRender
:
function
()
{
// Load the photos from the previous steps
$
(
'#face_image'
)[
0
].
src
=
this
.
model
.
get
(
'faceImage'
);
$
(
'#photo_id_image'
)[
0
].
src
=
this
.
model
.
get
(
'identificationImage'
);
...
...
@@ -49,6 +54,8 @@ var edx = edx || {};
},
submitPhotos
:
function
()
{
var
fullName
=
$
(
'#new-name'
).
val
();
// Disable the submit button to prevent duplicate submissions
$
(
'#next_step_button'
).
addClass
(
'is-disabled'
);
...
...
@@ -59,30 +66,28 @@ var edx = edx || {};
this
.
listenToOnce
(
this
.
model
,
'error'
,
_
.
bind
(
this
.
handleSubmissionError
,
this
)
);
// Submit
this
.
model
.
set
(
'fullName'
,
$
(
'#new-name'
).
val
()
);
if
(
fullName
)
{
this
.
model
.
set
(
'fullName'
,
fullName
);
}
this
.
model
.
save
();
},
handleSubmissionError
:
function
(
xhr
)
{
var
isConfirmChecked
=
$
(
"#confirm_pics_good"
).
prop
(
'checked'
),
errorMsg
=
gettext
(
'An unexpected error occurred. Please try again later.'
);
// Re-enable the submit button to allow the user to retry
var
isConfirmChecked
=
$
(
'#confirm_pics_good'
).
prop
(
'checked'
);
$
(
'#next_step_button'
).
toggleClass
(
'is-disabled'
,
!
isConfirmChecked
);
// Display the error
if
(
xhr
.
status
===
400
)
{
this
.
errorModel
.
set
({
errorTitle
:
gettext
(
'Could not submit photos'
),
errorMsg
:
xhr
.
responseText
,
shown
:
true
});
errorMsg
=
xhr
.
responseText
;
}
else
{
this
.
errorModel
.
set
({
errorTitle
:
gettext
(
'Could not submit photos'
),
errorMsg
:
gettext
(
'An unexpected error occurred. Please try again later.'
)
,
errorMsg
:
errorMsg
,
shown
:
true
});
}
},
expandCallback
:
function
(
event
)
{
...
...
lms/static/js/verify_student/views/step_view.js
View file @
d3459be0
...
...
@@ -26,19 +26,11 @@
},
render
:
function
()
{
var
templateHtml
=
$
(
"#"
+
this
.
templateName
+
"-tpl"
).
html
(),
templateContext
=
{
nextStepNum
:
this
.
nextStepNum
,
nextStepTitle
:
this
.
nextStepTitle
};
// Include step-specific information from the server
// (passed in from data- attributes to the parent view)
_
.
extend
(
templateContext
,
this
.
stepData
);
var
templateHtml
=
$
(
"#"
+
this
.
templateName
+
"-tpl"
).
html
();
// Allow subclasses to add additional information
// to the template context, perhaps asynchronously.
this
.
updateContext
(
t
emplateContext
).
done
(
this
.
updateContext
(
t
his
.
templateContext
()
).
done
(
function
(
templateContext
)
{
// Render the template into the DOM
$
(
this
.
el
).
html
(
_
.
template
(
templateHtml
,
templateContext
)
);
...
...
@@ -47,6 +39,8 @@
this
.
postRender
();
}
).
fail
(
_
.
bind
(
this
.
handleError
,
this
)
);
return
this
;
},
handleResponse
:
function
(
data
)
{
...
...
@@ -58,10 +52,8 @@
// Include step-specific information
_
.
extend
(
context
,
this
.
stepData
);
this
.
renderedHtml
=
_
.
template
(
data
,
context
);
$
(
this
.
el
).
html
(
this
.
renderedHtml
);
this
.
postRender
();
// Track a virtual pageview, for easy funnel reconstruction.
window
.
analytics
.
page
(
'verification'
,
this
.
templateName
);
},
handleError
:
function
(
errorTitle
,
errorMsg
)
{
...
...
@@ -72,6 +64,26 @@
});
},
templateContext
:
function
()
{
var
context
=
{
nextStepNum
:
this
.
nextStepNum
,
nextStepTitle
:
this
.
nextStepTitle
};
return
_
.
extend
(
context
,
this
.
defaultContext
(),
this
.
stepData
);
},
/**
* Provide default values for the template context.
* Subclasses can use this to fill in values that
* the underscore templates expect to be defined.
* This is especially useful for testing, so that the
* tests can pass in only the values relevant
* to the test.
*/
defaultContext
:
function
()
{
return
{};
},
/**
* Subclasses can override this to add information to
* the template context. This returns an asynchronous
...
...
lms/static/js/verify_student/views/webcam_photo_view.js
View file @
d3459be0
...
...
@@ -13,9 +13,10 @@
template
:
"#webcam_photo-tpl"
,
videoCaptureBackend
:
{
backends
:
[
{
name
:
"html5"
,
html5
:
{
initialize
:
function
(
obj
)
{
this
.
URL
=
(
window
.
URL
||
window
.
webkitURL
);
this
.
video
=
obj
.
video
||
""
;
...
...
@@ -90,7 +91,9 @@
}
},
flash
:
{
{
name
:
"flash"
,
initialize
:
function
(
obj
)
{
this
.
wrapper
=
obj
.
wrapper
||
""
;
this
.
imageData
=
""
;
...
...
@@ -193,15 +196,18 @@
// so we don't need to keep checking.
}
}
},
videoBackendPriority
:
[
'html5'
,
'flash'
],
],
initialize
:
function
(
obj
)
{
this
.
submitButton
=
obj
.
submitButton
||
""
;
this
.
modelAttribute
=
obj
.
modelAttribute
||
""
;
this
.
errorModel
=
obj
.
errorModel
||
{};
this
.
backend
=
this
.
chooseVideoCaptureBackend
();
this
.
errorModel
=
obj
.
errorModel
||
null
;
this
.
backend
=
_
.
find
(
obj
.
backends
||
this
.
backends
,
function
(
backend
)
{
return
backend
.
isSupported
();
}
);
if
(
!
this
.
backend
)
{
this
.
handleError
(
...
...
@@ -232,6 +238,7 @@
// Initialize the video capture backend
// We need to do this after rendering the template
// so that the backend has the opportunity to modify the DOM.
if
(
this
.
backend
)
{
this
.
backend
.
initialize
({
wrapper
:
"#camera"
,
video
:
'#photo_id_video'
,
...
...
@@ -242,6 +249,10 @@
$
(
"#webcam_reset_button"
,
this
.
el
).
on
(
'click'
,
_
.
bind
(
this
.
reset
,
this
)
);
$
(
"#webcam_capture_button"
,
this
.
el
).
on
(
'click'
,
_
.
bind
(
this
.
capture
,
this
)
);
// Show the capture button
$
(
"#webcam_capture_button"
,
this
.
el
).
removeClass
(
'is-hidden'
);
}
return
this
;
},
...
...
@@ -252,9 +263,12 @@
// Reset the video capture
this
.
backend
.
reset
();
// Reset data on the model
this
.
model
.
set
(
this
.
modelAttribute
,
""
);
// Go back to the initial button state
$
(
"#webcam_reset_button"
,
this
.
el
).
hide
(
);
$
(
"#webcam_capture_button"
,
this
.
el
).
show
(
);
$
(
"#webcam_reset_button"
,
this
.
el
).
addClass
(
'is-hidden'
);
$
(
"#webcam_capture_button"
,
this
.
el
).
removeClass
(
'is-hidden'
);
},
capture
:
function
()
{
...
...
@@ -267,8 +281,8 @@
this
.
trigger
(
'imageCaptured'
);
// Hide the capture button, and show the reset button
$
(
"#webcam_capture_button"
,
this
.
el
).
hide
(
);
$
(
"#webcam_reset_button"
,
this
.
el
).
show
(
);
$
(
"#webcam_capture_button"
,
this
.
el
).
addClass
(
'is-hidden'
);
$
(
"#webcam_reset_button"
,
this
.
el
).
removeClass
(
'is-hidden'
);
// Save the data to the model
this
.
model
.
set
(
this
.
modelAttribute
,
this
.
backend
.
getImageData
()
);
...
...
@@ -278,30 +292,20 @@
}
},
chooseVideoCaptureBackend
:
function
()
{
var
i
,
backendName
,
backend
;
for
(
i
=
0
;
i
<
this
.
videoBackendPriority
.
length
;
i
++
)
{
backendName
=
this
.
videoBackendPriority
[
i
];
backend
=
this
.
videoCaptureBackend
[
backendName
];
if
(
backend
.
isSupported
()
)
{
return
backend
;
}
}
},
handleError
:
function
(
errorTitle
,
errorMsg
)
{
// Hide the buttons
$
(
"#webcam_capture_button"
,
this
.
el
).
hide
(
);
$
(
"#webcam_reset_button"
,
this
.
el
).
hide
(
);
$
(
"#webcam_capture_button"
,
this
.
el
).
addClass
(
'is-hidden'
);
$
(
"#webcam_reset_button"
,
this
.
el
).
addClass
(
'is-hidden'
);
// Show the error message
if
(
this
.
errorModel
)
{
this
.
errorModel
.
set
({
errorTitle
:
errorTitle
,
errorMsg
:
errorMsg
,
shown
:
true
});
}
}
});
})(
jQuery
,
_
,
Backbone
,
gettext
);
lms/static/js_test.yml
View file @
d3459be0
...
...
@@ -79,6 +79,7 @@ fixture_paths:
-
templates/dashboard
-
templates/student_account
-
templates/student_profile
-
templates/verify_student
-
templates/file-upload.underscore
requirejs
:
...
...
lms/templates/verify_student/enrollment_confirmation_step.underscore
View file @
d3459be0
<div class="wrapper-content-main">
<div class="wrapper-content-main
enrollment-confirmation-step
">
<article class="content-main">
<h3 class="title"><%- gettext( "Congratulations! You are now enrolled in the verified track." ) %></h3>
<div class="instruction">
...
...
lms/templates/verify_student/face_photo_step.underscore
View file @
d3459be0
<div id="wrapper-facephoto" class="wrapper-view block-photo">
<div id="wrapper-facephoto" class="wrapper-view block-photo
face-photo-step
">
<div class="facephoto view">
<h3 class="title"><%- gettext( "Take Your Photo" ) %></h3>
<div class="instruction">
...
...
lms/templates/verify_student/id_photo_step.underscore
View file @
d3459be0
<div id="wrapper-idphoto" class="wrapper-view block-photo">
<div id="wrapper-idphoto" class="wrapper-view block-photo
id-photo-step
">
<div class="idphoto view">
<h3 class="title"><%- gettext( "Show Us Your ID" ) %></h3>
<div class="instruction">
...
...
lms/templates/verify_student/intro_step.underscore
View file @
d3459be0
<div class="wrapper-content-main">
<div class="wrapper-content-main
intro-step
">
<article class="content-main">
<h3 class="title"><%- introTitle %></h3>
<div class="instruction"><p><%- introMsg %></p></div>
...
...
@@ -9,11 +9,11 @@
<nav class="nav-wizard is-ready">
<ol class="wizard-steps">
<li class="wizard-step">
<a class="next action-primary" <% if (
isActive == "False"
) { %>disabled="true"<% } %> id="next_step_button" href="?skip-first-step=1">
<% if (
isActive == "False"
) { %>
<a class="next action-primary" <% if (
!isActive
) { %>disabled="true"<% } %> id="next_step_button" href="?skip-first-step=1">
<% if (
!isActive
) { %>
<%- gettext( "Activate Your Account" ) %>
<% } else { %>
<%- _.sprintf( gettext( "Go to Step %
s" ), nextStepNum
) %>: <%- nextStepTitle %>
<%- _.sprintf( gettext( "Go to Step %
(stepNumber)s" ), { stepNumber: nextStepNum }
) %>: <%- nextStepTitle %>
<% } %>
</a>
</li>
...
...
lms/templates/verify_student/make_payment_step.underscore
View file @
d3459be0
<div id="wrapper-review" class="wrapper-view">
<div id="wrapper-review" class="wrapper-view
make-payment-step
">
<div class="review view">
<h3 class="title"><%- gettext( "Make Payment" ) %></h3>
<div class="instruction">
...
...
@@ -7,7 +7,7 @@
<div class="requirements-container"></div>
<% if ( isActive
== "True"
) { %>
<% if ( isActive ) { %>
<div class="wrapper-task">
<ol class="review-tasks">
<% if ( suggestedPrices.length > 0 ) { %>
...
...
@@ -79,13 +79,15 @@
<nav class="nav-wizard is-ready">
<ol class="wizard-steps">
<li class="wizard-step">
<% if ( isActive ) { %>
<a class="next action-primary is-disabled" id="pay_button">
<% if ( isActive == "False" ) { %>
<%- gettext( "Activate Your Account" ) %>
<% } else { %>
<%- gettext( "Go to payment" ) %>
<% } %>
</a>
<% } else { %>
<a class="next action-primary is-disabled" id="activate_button">
<%- gettext( "Activate Your Account" ) %>
</a>
<% } %>
</li>
</ol>
</nav>
...
...
lms/templates/verify_student/pay_and_verify.html
View file @
d3459be0
...
...
@@ -71,7 +71,7 @@ from verify_student.views import PayAndVerifyView
data-current-step=
'${current_step}'
data-requirements=
'${json.dumps(requirements)}'
data-msg-key=
'${message_key}'
data-is-active=
"${is_active}"
data-is-active=
'${is_active}'
data-intro-title=
'${messages.intro_title}'
data-intro-msg=
'${messages.intro_msg}'
></div>
...
...
lms/templates/verify_student/payment_confirmation_step.underscore
View file @
d3459be0
<div class="wrapper-content-main">
<div class="wrapper-content-main
payment-confirmation-step
">
<article class="content-main">
<h3 class="title"><%- gettext( "Congratulations! You are now enrolled in the verified track." ) %></h3>
<div class="instruction">
...
...
lms/templates/verify_student/progress.underscore
View file @
d3459be0
<div class="wrapper-progress">
<div class="wrapper-progress
progress
">
<section class="progress">
<h3 class="sr title"><%- gettext("Your Progress") %></h3>
...
...
lms/templates/verify_student/review_photos_step.underscore
View file @
d3459be0
<div id="wrapper-review" class="wrapper-view">
<div id="wrapper-review" class="wrapper-view
review-photos-step
">
<div class="review view">
<h3 class="title"><%- gettext( "Verify Your Submission" ) %></h3>
<div class="instruction">
...
...
lms/templates/verify_student/webcam_photo.underscore
View file @
d3459be0
...
...
@@ -9,13 +9,13 @@
<div class="controls photo-controls">
<ul class="list-controls">
<li class="control control-retake
" id="webcam_reset_button" style="display: none;
">
<li class="control control-retake
is-hidden" id="webcam_reset_button
">
<a class="action action-redo">
<i class="icon-undo"></i> <span class="sr"><%- gettext( "Retake" ) %></span>
</a>
</li>
<li class="control control-do" id="webcam_capture_button">
<li class="control control-do
is-hidden
" id="webcam_capture_button">
<a class="action action-do">
<i class="icon-camera"></i> <span class="sr"><%- gettext( "Take photo" ) %></span>
</a>
...
...
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