Commit 1b0cda24 by muzaffaryousaf Committed by Usman Khalid

Js test fixes for lms and lms-coffee.

parent c728c9d3
...@@ -78,6 +78,15 @@ ...@@ -78,6 +78,15 @@
}; };
} }
}; };
},
toHaveIndex: function () {
return {
compare: function (actual, expected) {
return {
pass: $(actual).index() === expected
};
}
};
} }
}); });
}); });
......
...@@ -91,6 +91,7 @@ define([ ...@@ -91,6 +91,7 @@ define([
}; };
beforeEach(function () { beforeEach(function () {
spyOn(window.history, 'pushState');
setFixtures('<div class="certificates-content"></div>'); setFixtures('<div class="certificates-content"></div>');
view = new CertificatesView({ view = new CertificatesView({
el: $('.certificates-content') el: $('.certificates-content')
......
...@@ -46,7 +46,7 @@ define([ ...@@ -46,7 +46,7 @@ define([
it('re-renders itself when its collection changes', function () { it('re-renders itself when its collection changes', function () {
var requests = AjaxHelpers.requests(this); var requests = AjaxHelpers.requests(this);
enrollmentView = createEnrollmentView().render(); enrollmentView = createEnrollmentView().render();
spyOn(enrollmentView, 'render').andCallThrough(); spyOn(enrollmentView, 'render').and.callThrough();
AjaxHelpers.respondWithJson(requests, [EnrollmentHelpers.mockEnrollmentData]); AjaxHelpers.respondWithJson(requests, [EnrollmentHelpers.mockEnrollmentData]);
expect(enrollmentView.render).toHaveBeenCalled(); expect(enrollmentView.render).toHaveBeenCalled();
}); });
......
...@@ -140,7 +140,7 @@ define([ ...@@ -140,7 +140,7 @@ define([
AjaxHelpers.respondWithJson(requests, _.extend({}, teamsData, teamAction === 'create' ? {id: '123'} : {})); AjaxHelpers.respondWithJson(requests, _.extend({}, teamsData, teamAction === 'create' ? {id: '123'} : {}));
expect(teamEditView.$('.create-team.wrapper-msg .copy').text().trim().length).toBe(0); expect(teamEditView.$('.create-team.wrapper-msg .copy').text().trim().length).toBe(0);
expect(Backbone.history.navigate.calls[0].args).toContain(expectedUrl); expect(Backbone.history.navigate.calls.mostRecent().args[0]).toBe(expectedUrl);
}; };
var assertValidationMessagesWhenFieldsEmpty = function(that) { var assertValidationMessagesWhenFieldsEmpty = function(that) {
...@@ -217,7 +217,7 @@ define([ ...@@ -217,7 +217,7 @@ define([
var assertRedirectsToCorrectUrlOnCancel = function(expectedUrl) { var assertRedirectsToCorrectUrlOnCancel = function(expectedUrl) {
var teamEditView = createEditTeamView(); var teamEditView = createEditTeamView();
teamEditView.$('.create-team.form-actions .action-cancel').click(); teamEditView.$('.create-team.form-actions .action-cancel').click();
expect(Backbone.history.navigate.calls[0].args).toContain(expectedUrl); expect(Backbone.history.navigate.calls.mostRecent().args[0]).toBe(expectedUrl);
}; };
describe('NewTeam', function () { describe('NewTeam', function () {
......
...@@ -250,7 +250,7 @@ define([ ...@@ -250,7 +250,7 @@ define([
expect(editButton.length).toEqual(1); expect(editButton.length).toEqual(1);
$(editButton).click(); $(editButton).click();
expect(Backbone.history.navigate.calls[0].args[0]).toContain('/edit-team'); expect(Backbone.history.navigate.calls.mostRecent().args[0]).toContain('/edit-team');
}); });
}); });
}); });
......
...@@ -65,12 +65,12 @@ define([ ...@@ -65,12 +65,12 @@ define([
var teamsView = createTopicTeamsView(); var teamsView = createTopicTeamsView();
spyOn(Backbone.history, 'navigate'); spyOn(Backbone.history, 'navigate');
teamsView.$('.browse-teams').click(); teamsView.$('.browse-teams').click();
expect(Backbone.history.navigate.calls[0].args).toContain('browse'); expect(Backbone.history.navigate.calls.mostRecent().args[0]).toBe('browse');
}); });
it('gives the search field focus when clicking on the search teams link', function () { it('gives the search field focus when clicking on the search teams link', function () {
var teamsView = createTopicTeamsView(); var teamsView = createTopicTeamsView();
spyOn($.fn, 'focus').andCallThrough(); spyOn($.fn, 'focus').and.callThrough();
teamsView.$('.search-teams').click(); teamsView.$('.search-teams').click();
expect(teamsView.$('.search-field').first().focus).toHaveBeenCalled(); expect(teamsView.$('.search-field').first().focus).toHaveBeenCalled();
}); });
...@@ -79,7 +79,7 @@ define([ ...@@ -79,7 +79,7 @@ define([
var teamsView = createTopicTeamsView(); var teamsView = createTopicTeamsView();
spyOn(Backbone.history, 'navigate'); spyOn(Backbone.history, 'navigate');
teamsView.$('a.create-team').click(); teamsView.$('a.create-team').click();
expect(Backbone.history.navigate.calls[0].args).toContain( expect(Backbone.history.navigate.calls.mostRecent().args[0]).toBe(
'topics/' + TeamSpecHelpers.testTopicID + '/create-team' 'topics/' + TeamSpecHelpers.testTopicID + '/create-team'
); );
}); });
......
...@@ -37,19 +37,25 @@ describe 'Calculator', -> ...@@ -37,19 +37,25 @@ describe 'Calculator', ->
$('form#calculator').submit() $('form#calculator').submit()
describe 'toggle', -> describe 'toggle', ->
it 'focuses the input when toggled', -> it 'focuses the input when toggled', (done)->
# Since the focus is called asynchronously, we need to self = this
# wait until focus() is called. focus = ()->
didFocus = false deferred = $.Deferred()
runs ->
spyOn($.fn, 'focus').andCallFake (elementName) -> didFocus = true
@calculator.toggle(jQuery.Event("click"))
waitsFor (-> didFocus), "focus() should have been called on the input", 1000 # Since the focus is called asynchronously, we need to
# wait until focus() is called.
spyOn($.fn, 'focus').and.callFake (elementName) ->
deferred.resolve()
runs -> self.calculator.toggle(jQuery.Event("click"))
expect($('#calculator_wrapper #calculator_input').focus).toHaveBeenCalled()
deferred.promise()
focus().then(
->
expect($('#calculator_wrapper #calculator_input').focus).toHaveBeenCalled()
).always(done)
it 'toggle the close button on the calculator button', -> it 'toggle the close button on the calculator button', ->
@calculator.toggle(jQuery.Event("click")) @calculator.toggle(jQuery.Event("click"))
...@@ -305,10 +311,10 @@ describe 'Calculator', -> ...@@ -305,10 +311,10 @@ describe 'Calculator', ->
'prevHint': calc 'prevHint': calc
$.each(cases, (key, data) -> $.each(cases, (key, data) ->
calc.hideHint.reset() calc.hideHint.calls.reset()
calc.prevHint.reset() calc.prevHint.calls.reset()
calc.nextHint.reset() calc.nextHint.calls.reset()
$.fn.focus.reset() $.fn.focus.calls.reset()
e = jQuery.Event('keydown', data.event or {}); e = jQuery.Event('keydown', data.event or {});
value = calc.handleKeyDownOnHint(e) value = calc.handleKeyDownOnHint(e)
...@@ -334,7 +340,7 @@ describe 'Calculator', -> ...@@ -334,7 +340,7 @@ describe 'Calculator', ->
describe 'calculate', -> describe 'calculate', ->
beforeEach -> beforeEach ->
$('#calculator_input').val '1+2' $('#calculator_input').val '1+2'
spyOn($, 'getWithPrefix').andCallFake (url, data, callback) -> spyOn($, 'getWithPrefix').and.callFake (url, data, callback) ->
callback({ result: 3 }) callback({ result: 3 })
@calculator.calculate() @calculator.calculate()
......
...@@ -5,7 +5,7 @@ describe 'FeedbackForm', -> ...@@ -5,7 +5,7 @@ describe 'FeedbackForm', ->
describe 'constructor', -> describe 'constructor', ->
beforeEach -> beforeEach ->
new FeedbackForm new FeedbackForm
spyOn($, 'postWithPrefix').andCallFake (url, data, callback, format) -> spyOn($, 'postWithPrefix').and.callFake (url, data, callback, format) ->
callback() callback()
it 'binds to the #feedback_button', -> it 'binds to the #feedback_button', ->
......
...@@ -13,7 +13,7 @@ jasmine.stubbedCaption = ...@@ -13,7 +13,7 @@ jasmine.stubbedCaption =
text: ['Caption at 0', 'Caption at 10000', 'Caption at 20000', 'Caption at 30000'] text: ['Caption at 0', 'Caption at 10000', 'Caption at 20000', 'Caption at 30000']
jasmine.stubRequests = -> jasmine.stubRequests = ->
spyOn($, 'ajax').andCallFake (settings) -> spyOn($, 'ajax').and.callFake (settings) ->
if match = settings.url.match /youtube\.com\/.+\/videos\/(.+)\?v=2&alt=jsonc/ if match = settings.url.match /youtube\.com\/.+\/videos\/(.+)\?v=2&alt=jsonc/
settings.success data: jasmine.stubbedMetadata[match[1]] settings.success data: jasmine.stubbedMetadata[match[1]]
else if match = settings.url.match /static\/subs\/(.+)\.srt\.sjson/ else if match = settings.url.match /static\/subs\/(.+)\.srt\.sjson/
...@@ -52,8 +52,6 @@ jasmine.stubVideoPlayer = (context, enableParts, createPlayer=true) -> ...@@ -52,8 +52,6 @@ jasmine.stubVideoPlayer = (context, enableParts, createPlayer=true) ->
if createPlayer if createPlayer
return new VideoPlayer(video: context.video) return new VideoPlayer(video: context.video)
spyOn(window, 'onunload')
# Stub Youtube API # Stub Youtube API
window.YT = window.YT =
PlayerState: PlayerState:
...@@ -65,7 +63,7 @@ window.YT = ...@@ -65,7 +63,7 @@ window.YT =
CUED: 5 CUED: 5
# Stub jQuery.cookie # Stub jQuery.cookie
$.cookie = jasmine.createSpy('jQuery.cookie').andReturn '1.0' $.cookie = jasmine.createSpy('jQuery.cookie').and.returnValue '1.0'
# Stub jQuery.qtip # Stub jQuery.qtip
$.fn.qtip = jasmine.createSpy 'jQuery.qtip' $.fn.qtip = jasmine.createSpy 'jQuery.qtip'
......
...@@ -25,7 +25,13 @@ describe 'Histogram', -> ...@@ -25,7 +25,13 @@ describe 'Histogram', ->
describe 'render', -> describe 'render', ->
it 'call flot with correct option', -> it 'call flot with correct option', ->
new Histogram(1, [[1, 1], [2, 2], [3, 3]]) new Histogram(1, [[1, 1], [2, 2], [3, 3]])
expect($.plot).toHaveBeenCalledWith $("#histogram_1"), [
firstArg = $.plot.calls.mostRecent().args[0]
secondArg = $.plot.calls.mostRecent().args[1]
thirdArg = $.plot.calls.mostRecent().args[2]
expect(firstArg.selector).toEqual($("#histogram_1").selector)
expect(secondArg).toEqual([
data: [[1, Math.log(2)], [2, Math.log(3)], [3, Math.log(4)]] data: [[1, Math.log(2)], [2, Math.log(3)], [3, Math.log(4)]]
bars: bars:
show: true show: true
...@@ -33,7 +39,8 @@ describe 'Histogram', -> ...@@ -33,7 +39,8 @@ describe 'Histogram', ->
lineWidth: 0 lineWidth: 0
fill: 1.0 fill: 1.0
color: "#b72121" color: "#b72121"
], ])
expect(thirdArg).toEqual(
xaxis: xaxis:
min: -1 min: -1
max: 4 max: 4
...@@ -44,3 +51,4 @@ describe 'Histogram', -> ...@@ -44,3 +51,4 @@ describe 'Histogram', ->
max: Math.log(4) * 1.1 max: Math.log(4) * 1.1
ticks: [[Math.log(2), '1'], [Math.log(3), '2'], [Math.log(4), '3']] ticks: [[Math.log(2), '1'], [Math.log(3), '2'], [Math.log(4), '3']]
labelWidth: 50 labelWidth: 50
)
...@@ -10,22 +10,22 @@ describe 'AutoEnrollment', -> ...@@ -10,22 +10,22 @@ describe 'AutoEnrollment', ->
expect(@autoenrollment.$browse_button).toHandle 'change' expect(@autoenrollment.$browse_button).toHandle 'change'
it 'binds the ajax call and the result will be success', -> it 'binds the ajax call and the result will be success', ->
spyOn($, "ajax").andCallFake((params) => spyOn($, "ajax").and.callFake((params) =>
params.success({row_errors: [], general_errors: [], warnings: []}) params.success({row_errors: [], general_errors: [], warnings: []})
{always: ->} {always: ->}
) )
# mock the render_notification_view which returns the html (since we are only using the existing notification model) # mock the render_notification_view which returns the html (since we are only using the existing notification model)
@autoenrollment.render_notification_view = jasmine.createSpy("render_notification_view(type, title, message, details) spy").andCallFake => @autoenrollment.render_notification_view = jasmine.createSpy("render_notification_view(type, title, message, details) spy").and.callFake =>
return '<div><div class="message message-confirmation"><h3 class="message-title">Success</h3><div class="message-copy"><p>All accounts were created successfully.</p></div></div><div>' return '<div><div class="message message-confirmation"><h3 class="message-title">Success</h3><div class="message-copy"><p>All accounts were created successfully.</p></div></div><div>'
submitCallback = jasmine.createSpy().andReturn() submitCallback = jasmine.createSpy().and.returnValue()
@autoenrollment.$student_enrollment_form.submit(submitCallback) @autoenrollment.$student_enrollment_form.submit(submitCallback)
@autoenrollment.$enrollment_signup_button.click() @autoenrollment.$enrollment_signup_button.click()
expect($('.results .message-copy').text()).toEqual('All accounts were created successfully.') expect($('.results .message-copy').text()).toEqual('All accounts were created successfully.')
expect(submitCallback).toHaveBeenCalled() expect(submitCallback).toHaveBeenCalled()
it 'binds the ajax call and the result will be error', -> it 'binds the ajax call and the result will be error', ->
spyOn($, "ajax").andCallFake((params) => spyOn($, "ajax").and.callFake((params) =>
params.success({ params.success({
row_errors: [{ row_errors: [{
'username': 'testuser1', 'username': 'testuser1',
...@@ -40,17 +40,17 @@ describe 'AutoEnrollment', -> ...@@ -40,17 +40,17 @@ describe 'AutoEnrollment', ->
{always: ->} {always: ->}
) )
# mock the render_notification_view which returns the html (since we are only using the existing notification model) # mock the render_notification_view which returns the html (since we are only using the existing notification model)
@autoenrollment.render_notification_view = jasmine.createSpy("render_notification_view(type, title, message, details) spy").andCallFake => @autoenrollment.render_notification_view = jasmine.createSpy("render_notification_view(type, title, message, details) spy").and.callFake =>
return '<div><div class="message message-error"><h3 class="message-title">Errors</h3><div class="message-copy"><p>The following errors were generated:</p><ul class="list-summary summary-items"><li class="summary-item">cannot read the line 2</li><li class="summary-item">testuser1 (testemail1@email.com): (Username already exists)</li></ul></div></div></div>' return '<div><div class="message message-error"><h3 class="message-title">Errors</h3><div class="message-copy"><p>The following errors were generated:</p><ul class="list-summary summary-items"><li class="summary-item">cannot read the line 2</li><li class="summary-item">testuser1 (testemail1@email.com): (Username already exists)</li></ul></div></div></div>'
submitCallback = jasmine.createSpy().andReturn() submitCallback = jasmine.createSpy().and.returnValue()
@autoenrollment.$student_enrollment_form.submit(submitCallback) @autoenrollment.$student_enrollment_form.submit(submitCallback)
@autoenrollment.$enrollment_signup_button.click() @autoenrollment.$enrollment_signup_button.click()
expect($('.results .list-summary').text()).toEqual('cannot read the line 2testuser1 (testemail1@email.com): (Username already exists)'); expect($('.results .list-summary').text()).toEqual('cannot read the line 2testuser1 (testemail1@email.com): (Username already exists)');
expect(submitCallback).toHaveBeenCalled() expect(submitCallback).toHaveBeenCalled()
it 'binds the ajax call and the result will be warnings', -> it 'binds the ajax call and the result will be warnings', ->
spyOn($, "ajax").andCallFake((params) => spyOn($, "ajax").and.callFake((params) =>
params.success({ params.success({
row_errors: [], row_errors: [],
general_errors: [], general_errors: [],
...@@ -63,10 +63,10 @@ describe 'AutoEnrollment', -> ...@@ -63,10 +63,10 @@ describe 'AutoEnrollment', ->
{always: ->} {always: ->}
) )
# mock the render_notification_view which returns the html (since we are only using the existing notification model) # mock the render_notification_view which returns the html (since we are only using the existing notification model)
@autoenrollment.render_notification_view = jasmine.createSpy("render_notification_view(type, title, message, details) spy").andCallFake => @autoenrollment.render_notification_view = jasmine.createSpy("render_notification_view(type, title, message, details) spy").and.callFake =>
return '<div><div class="message message-warning"><h3 class="message-title">Warnings</h3><div class="message-copy"><p>The following warnings were generated:</p><ul class="list-summary summary-items"><li class="summary-item">user1 (user1email): (email is in valid)</li></ul></div></div></div>' return '<div><div class="message message-warning"><h3 class="message-title">Warnings</h3><div class="message-copy"><p>The following warnings were generated:</p><ul class="list-summary summary-items"><li class="summary-item">user1 (user1email): (email is in valid)</li></ul></div></div></div>'
submitCallback = jasmine.createSpy().andReturn() submitCallback = jasmine.createSpy().and.returnValue()
@autoenrollment.$student_enrollment_form.submit(submitCallback) @autoenrollment.$student_enrollment_form.submit(submitCallback)
@autoenrollment.$enrollment_signup_button.click() @autoenrollment.$enrollment_signup_button.click()
expect($('.results .list-summary').text()).toEqual('user1 (user1email): (email is in valid)') expect($('.results .list-summary').text()).toEqual('user1 (user1email): (email is in valid)')
......
...@@ -3,15 +3,30 @@ describe "RequireJS namespacing", -> ...@@ -3,15 +3,30 @@ describe "RequireJS namespacing", ->
# Jasmine does not provide a way to use the typeof operator. We need # Jasmine does not provide a way to use the typeof operator. We need
# to create our own custom matchers so that a TypeError is not thrown. # to create our own custom matchers so that a TypeError is not thrown.
@addMatchers jasmine.addMatchers
requirejsTobeUndefined: -> requirejsTobeUndefined: ->
typeof requirejs is "undefined" {
compare: ->
{
pass: typeof requirejs is "undefined"
}
}
requireTobeUndefined: -> requireTobeUndefined: ->
typeof require is "undefined" {
compare: ->
{
pass: typeof require is "undefined"
}
}
defineTobeUndefined: -> defineTobeUndefined: ->
typeof define is "undefined" {
compare: ->
{
pass: typeof define is "undefined"
}
}
it "check that the RequireJS object is present in the global namespace", -> it "check that the RequireJS object is present in the global namespace", ->
...@@ -34,12 +49,13 @@ describe "RequireJS namespacing", -> ...@@ -34,12 +49,13 @@ describe "RequireJS namespacing", ->
describe "RequireJS module creation", -> describe "RequireJS module creation", ->
inDefineCallback = undefined inDefineCallback = undefined
inRequireCallback = undefined inRequireCallback = undefined
it "check that we can use RequireJS to define() and require() a module", -> it "check that we can use RequireJS to define() and require() a module", (done) ->
d1 = $.Deferred()
d2 = $.Deferred()
# Because Require JS works asynchronously when defining and requiring # Because Require JS works asynchronously when defining and requiring
# modules, we need to use the special Jasmine functions runs(), and # modules, we need to use the special Jasmine functions runs(), and
# waitsFor() to set up this test. # waitsFor() to set up this test.
runs -> func = () ->
# Initialize the variable that we will test for. They will be set # Initialize the variable that we will test for. They will be set
# to true in the appropriate callback functions called by Require # to true in the appropriate callback functions called by Require
...@@ -52,6 +68,8 @@ describe "RequireJS module creation", -> ...@@ -52,6 +68,8 @@ describe "RequireJS module creation", ->
RequireJS.define "test_module", [], -> RequireJS.define "test_module", [], ->
inDefineCallback = true inDefineCallback = true
d1.resolve()
# This module returns an object. It can be accessed via the # This module returns an object. It can be accessed via the
# Require JS require() function. # Require JS require() function.
module_status: "OK" module_status: "OK"
...@@ -66,24 +84,12 @@ describe "RequireJS module creation", -> ...@@ -66,24 +84,12 @@ describe "RequireJS module creation", ->
# property. # property.
expect(test_module.module_status).toBe "OK" expect(test_module.module_status).toBe "OK"
d2.resolve()
func()
# We will wait for a specified amount of time (1 second), before # We will wait before checking if our module was defined and that we were able to require() the module.
# checking if our module was defined and that we were able to $.when(d1, d2).done(->
# require() the module. # The final test behavior
waitsFor (->
# If at least one of the callback functions was not reached, we
# fail this test.
return false if (inDefineCallback isnt true) or (inRequireCallback isnt true)
# Both of the callbacks were reached.
true
), "We should eventually end up in the defined callback", 1000
# The final test behavior, after waitsFor() finishes waiting.
runs ->
expect(inDefineCallback).toBeTruthy() expect(inDefineCallback).toBeTruthy()
expect(inRequireCallback).toBeTruthy() expect(inRequireCallback).toBeTruthy()
).always(done)
...@@ -62,7 +62,7 @@ class @Calculator ...@@ -62,7 +62,7 @@ class @Calculator
isExpanded = true isExpanded = true
$calcWrapper $calcWrapper
.find('input, a,') .find('input, a')
.attr 'tabindex', 0 .attr 'tabindex', 0
# TODO: Investigate why doing this without the timeout causes it to jump # TODO: Investigate why doing this without the timeout causes it to jump
# down to the bottom of the page. I suspect it's because it's putting the # down to the bottom of the page. I suspect it's because it's putting the
......
...@@ -18,7 +18,11 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers ...@@ -18,7 +18,11 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers
); );
timerCallback = jasmine.createSpy('timerCallback'); timerCallback = jasmine.createSpy('timerCallback');
jasmine.Clock.useMock(); jasmine.clock().install();
});
afterEach(function() {
jasmine.clock().uninstall();
}); });
var createBookmarkButtonView = function(isBookmarked) { var createBookmarkButtonView = function(isBookmarked) {
...@@ -80,7 +84,7 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers ...@@ -80,7 +84,7 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers
var bookmarkButtonView = createBookmarkButtonView(firstActionData.bookmarked); var bookmarkButtonView = createBookmarkButtonView(firstActionData.bookmarked);
verifyBookmarkButtonState(bookmarkButtonView, firstActionData.bookmarked); verifyBookmarkButtonState(bookmarkButtonView, firstActionData.bookmarked);
spyOn(bookmarkButtonView, firstActionData.handler).andCallThrough(); spyOn(bookmarkButtonView, firstActionData.handler).and.callThrough();
spyOnEvent(bookmarkButtonView.$el, firstActionData.event); spyOnEvent(bookmarkButtonView.$el, firstActionData.event);
bookmarkButtonView.$el.click(); bookmarkButtonView.$el.click();
...@@ -96,12 +100,12 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers ...@@ -96,12 +100,12 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers
expect(bookmarkButtonView[firstActionData.handler]).toHaveBeenCalled(); expect(bookmarkButtonView[firstActionData.handler]).toHaveBeenCalled();
AjaxHelpers.respondWithJson(requests, {}); AjaxHelpers.respondWithJson(requests, {});
expect(firstActionData.event).toHaveBeenTriggeredOn(bookmarkButtonView.$el); expect(firstActionData.event).toHaveBeenTriggeredOn(bookmarkButtonView.$el);
bookmarkButtonView[firstActionData.handler].reset(); bookmarkButtonView[firstActionData.handler].calls.reset();
expect(bookmarkButtonView.$el).not.toHaveAttr('disabled'); expect(bookmarkButtonView.$el).not.toHaveAttr('disabled');
verifyBookmarkButtonState(bookmarkButtonView, secondActionData.bookmarked); verifyBookmarkButtonState(bookmarkButtonView, secondActionData.bookmarked);
spyOn(bookmarkButtonView, secondActionData.handler).andCallThrough(); spyOn(bookmarkButtonView, secondActionData.handler).and.callThrough();
spyOnEvent(bookmarkButtonView.$el, secondActionData.event); spyOnEvent(bookmarkButtonView.$el, secondActionData.event);
bookmarkButtonView.$el.click(); bookmarkButtonView.$el.click();
...@@ -154,7 +158,7 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers ...@@ -154,7 +158,7 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers
expect($messageBanner.text().trim()).toBe(bookmarkButtonView.errorMessage); expect($messageBanner.text().trim()).toBe(bookmarkButtonView.errorMessage);
jasmine.Clock.tick(5001); jasmine.clock().tick(5001);
expect($messageBanner.text().trim()).toBe(''); expect($messageBanner.text().trim()).toBe('');
}); });
}); });
......
...@@ -24,10 +24,16 @@ define(['backbone', ...@@ -24,10 +24,16 @@ define(['backbone',
'templates/bookmarks/bookmarks-list' 'templates/bookmarks/bookmarks-list'
] ]
); );
spyOn(Logger, 'log').andReturn($.Deferred().resolve()); spyOn(Logger, 'log').and.returnValue($.Deferred().resolve());
this.addMatchers({ jasmine.addMatchers({
toHaveBeenCalledWithUrl: function (expectedUrl) { toHaveBeenCalledWithUrl: function () {
return expectedUrl === this.actual.argsForCall[0][0].target.pathname; return {
compare: function (actual, expectedUrl) {
return {
pass: expectedUrl === actual.calls.mostRecent().args[0].currentTarget.pathname
};
}
};
} }
}); });
...@@ -117,7 +123,7 @@ define(['backbone', ...@@ -117,7 +123,7 @@ define(['backbone',
it("has correct behavior for bookmarks button", function () { it("has correct behavior for bookmarks button", function () {
var requests = AjaxHelpers.requests(this); var requests = AjaxHelpers.requests(this);
spyOn(bookmarksButtonView, 'toggleBookmarksListView').andCallThrough(); spyOn(bookmarksButtonView, 'toggleBookmarksListView').and.callThrough();
bookmarksButtonView.delegateEvents(); bookmarksButtonView.delegateEvents();
......
...@@ -2,18 +2,21 @@ define(['common/js/spec_helpers/ajax_helpers', 'js/ccx/schedule'], ...@@ -2,18 +2,21 @@ define(['common/js/spec_helpers/ajax_helpers', 'js/ccx/schedule'],
function(AjaxHelpers) { function(AjaxHelpers) {
describe("edx.ccx.schedule.ScheduleView", function() { describe("edx.ccx.schedule.ScheduleView", function() {
var view = null; var view = null;
var data;
beforeEach(function() { beforeEach(function() {
loadFixtures("js/fixtures/ccx/schedule.html"); loadFixtures("js/fixtures/ccx/schedule.html");
var scheduleFixture = readFixtures("templates/ccx/schedule.underscore"); var scheduleFixture = readFixtures("templates/ccx/schedule.underscore");
appendSetFixtures("<div id=\"schedule_template\">" + scheduleFixture + "</div>"); appendSetFixtures(
"<script id=\"schedule_template\" type=\"text/template\" >" + scheduleFixture + "</script>"
);
schedule_template = _.template($('#schedule_template').html()); schedule_template = _.template($('#schedule_template').html());
save_url = 'save_ccx'; save_url = 'save_ccx';
$.fn.leanModal = function(param) { $.fn.leanModal = function(param) {
return true; return true;
} };
data = [{ data = [{
"category": "chapter", "category": "chapter",
...@@ -44,10 +47,8 @@ define(['common/js/spec_helpers/ajax_helpers', 'js/ccx/schedule'], ...@@ -44,10 +47,8 @@ define(['common/js/spec_helpers/ajax_helpers', 'js/ccx/schedule'],
] ]
}]; }];
view = new edx.ccx.schedule.ScheduleView({el: $('#new-ccx-schedule')}); view = new edx.ccx.schedule.ScheduleView({el: $('#new-ccx-schedule')});
view.schedule_collection.set(data) view.schedule_collection.set(data);
view.render(); view.render();
}); });
it("verifies correct view setup", function() { it("verifies correct view setup", function() {
......
...@@ -29,7 +29,7 @@ define(['common/js/spec_helpers/template_helpers', 'common/js/spec_helpers/ajax_ ...@@ -29,7 +29,7 @@ define(['common/js/spec_helpers/template_helpers', 'common/js/spec_helpers/ajax_
// This function gets passed the dynamically constructed // This function gets passed the dynamically constructed
// form with signed payment parameters from the LMS server, // form with signed payment parameters from the LMS server,
// so we can verify that the form is constructed correctly. // so we can verify that the form is constructed correctly.
spyOn(view, 'submitPaymentForm').andCallFake(function() {}); spyOn(view, 'submitPaymentForm').and.callFake(function() {});
// Stub the analytics event tracker // Stub the analytics event tracker
window.analytics = jasmine.createSpyObj('analytics', ['track']); window.analytics = jasmine.createSpyObj('analytics', ['track']);
...@@ -64,7 +64,7 @@ define(['common/js/spec_helpers/template_helpers', 'common/js/spec_helpers/ajax_ ...@@ -64,7 +64,7 @@ define(['common/js/spec_helpers/template_helpers', 'common/js/spec_helpers/ajax_
// We stub out the actual submission of the form to avoid // We stub out the actual submission of the form to avoid
// leaving the current page during the test. // leaving the current page during the test.
expect(view.submitPaymentForm).toHaveBeenCalled(); expect(view.submitPaymentForm).toHaveBeenCalled();
var form = view.submitPaymentForm.mostRecentCall.args[0]; var form = view.submitPaymentForm.calls.mostRecent().args[0];
expect(form.serialize()).toEqual($.param(PAYMENT_PARAMS)); expect(form.serialize()).toEqual($.param(PAYMENT_PARAMS));
expect(form.attr('method')).toEqual("post"); expect(form.attr('method')).toEqual("post");
expect(form.attr('action')).toEqual(PAYMENT_URL); expect(form.attr('action')).toEqual(PAYMENT_URL);
......
...@@ -14,15 +14,10 @@ define(['js/dashboard/dropdown', 'jquery.simulate'], ...@@ -14,15 +14,10 @@ define(['js/dashboard/dropdown', 'jquery.simulate'],
verifyDropdownNotVisible = function() { verifyDropdownNotVisible = function() {
expect($(dropdownSelector)).not.toBeVisible(); expect($(dropdownSelector)).not.toBeVisible();
}, },
waitForElementToBeFocused = function(element, desc) { waitForElementToBeFocused = function(element, done) {
// This is being used instead of toBeFocused which is flaky jasmine.waitUntil(function () {
waitsFor( return element === document.activeElement;
function () { }).always(done);
return element === document.activeElement;
},
desc + ' element to have focus',
500
);
}, },
openDropDownMenu = function() { openDropDownMenu = function() {
verifyDropdownNotVisible(); verifyDropdownNotVisible();
...@@ -47,39 +42,39 @@ define(['js/dashboard/dropdown', 'jquery.simulate'], ...@@ -47,39 +42,39 @@ define(['js/dashboard/dropdown', 'jquery.simulate'],
clickToggleButton(); clickToggleButton();
verifyDropdownNotVisible(); verifyDropdownNotVisible();
}); });
it("ESCAPE will close dropdown and return focus to the button", function() { it("ESCAPE will close dropdown and return focus to the button", function(done) {
openDropDownMenu(); openDropDownMenu();
keydown({ keyCode: keys.ESCAPE }); keydown({ keyCode: keys.ESCAPE });
verifyDropdownNotVisible(); verifyDropdownNotVisible();
waitForElementToBeFocused($(toggleButtonSelector)[0], "button"); waitForElementToBeFocused($(toggleButtonSelector)[0], done);
}); });
it("SPACE will close dropdown and return focus to the button", function() { it("SPACE will close dropdown and return focus to the button", function(done) {
openDropDownMenu(); openDropDownMenu();
keydown({ keyCode: keys.SPACE }); keydown({ keyCode: keys.SPACE });
verifyDropdownNotVisible(); verifyDropdownNotVisible();
waitForElementToBeFocused($(toggleButtonSelector)[0], "button"); waitForElementToBeFocused($(toggleButtonSelector)[0], done);
}); });
describe("Focus is trapped when navigating with", function() { describe("Focus is trapped when navigating with", function() {
it("TAB key", function() { it("TAB key", function(done) {
openDropDownMenu(); openDropDownMenu();
keydown({ keyCode: keys.TAB }); keydown({ keyCode: keys.TAB });
waitForElementToBeFocused($(dropdownItemSelector)[0], "first"); waitForElementToBeFocused($(dropdownItemSelector)[0], done);
}); });
it("DOWN key", function() { it("DOWN key", function(done) {
openDropDownMenu(); openDropDownMenu();
keydown({ keyCode: keys.DOWN }); keydown({ keyCode: keys.DOWN });
waitForElementToBeFocused($(dropdownItemSelector)[0], "first"); waitForElementToBeFocused($(dropdownItemSelector)[0], done);
}); });
it("TAB key + SHIFT key", function() { it("TAB key + SHIFT key", function(done) {
openDropDownMenu(); openDropDownMenu();
keydown({ keyCode: keys.TAB, shiftKey: true }); keydown({ keyCode: keys.TAB, shiftKey: true });
waitForElementToBeFocused($(dropdownItemSelector)[1], "last"); waitForElementToBeFocused($(dropdownItemSelector)[1], done);
}); });
it("UP key", function() { it("UP key", function(done) {
openDropDownMenu(); openDropDownMenu();
keydown({ keyCode: keys.UP }); keydown({ keyCode: keys.UP });
waitForElementToBeFocused($(dropdownItemSelector)[1], "last"); waitForElementToBeFocused($(dropdownItemSelector)[1], done);
}); });
}); });
}); });
......
...@@ -121,7 +121,7 @@ define([ ...@@ -121,7 +121,7 @@ define([
it('loads more', function () { it('loads more', function () {
var requests = AjaxHelpers.requests(this); var requests = AjaxHelpers.requests(this);
jasmine.Clock.useMock(); jasmine.clock().install();
$('.discovery-input').val('test'); $('.discovery-input').val('test');
$('.discovery-submit').trigger('click'); $('.discovery-submit').trigger('click');
AjaxHelpers.respondWithJson(requests, JSON_RESPONSE); AjaxHelpers.respondWithJson(requests, JSON_RESPONSE);
...@@ -129,12 +129,14 @@ define([ ...@@ -129,12 +129,14 @@ define([
expect($('.courses-listing .course-title')).toContainHtml('edX Demonstration Course'); expect($('.courses-listing .course-title')).toContainHtml('edX Demonstration Course');
window.scroll(0, $(document).height()); window.scroll(0, $(document).height());
$(window).trigger('scroll'); $(window).trigger('scroll');
jasmine.Clock.tick(500); jasmine.clock().tick(500);
// TODO: determine why the search API is invoked twice // TODO: determine why the search API is invoked twice
AjaxHelpers.respondWithJson(requests, JSON_RESPONSE); AjaxHelpers.respondWithJson(requests, JSON_RESPONSE);
AjaxHelpers.respondWithJson(requests, JSON_RESPONSE); AjaxHelpers.respondWithJson(requests, JSON_RESPONSE);
expect($('.courses-listing article').length).toEqual(2); expect($('.courses-listing article').length).toEqual(2);
jasmine.clock().uninstall();
}); });
it('displays not found message', function () { it('displays not found message', function () {
......
...@@ -43,8 +43,8 @@ define([ ...@@ -43,8 +43,8 @@ define([
it('renders', function () { it('renders', function () {
var data = this.view.model.attributes; var data = this.view.model.attributes;
expect(this.view.$el).toContainHtml(data.content.display_name); expect(this.view.$el).toContainHtml(data.content.display_name);
expect(this.view.$el).toContain('a[href="/courses/' + data.course + '/about"]'); expect(this.view.$el).toContainElement('a[href="/courses/' + data.course + '/about"]');
expect(this.view.$el).toContain('img[src="' + data.image_url + '"]'); expect(this.view.$el).toContainElement('img[src="' + data.image_url + '"]');
expect(this.view.$el.find('.course-name')).toContainHtml(data.org); expect(this.view.$el.find('.course-name')).toContainHtml(data.org);
expect(this.view.$el.find('.course-name')).toContainHtml(data.content.number); expect(this.view.$el.find('.course-name')).toContainHtml(data.content.number);
expect(this.view.$el.find('.course-name')).toContainHtml(data.content.display_name); expect(this.view.$el.find('.course-name')).toContainHtml(data.content.display_name);
......
...@@ -34,7 +34,7 @@ define([ ...@@ -34,7 +34,7 @@ define([
describe('discovery.views.CoursesListing', function () { describe('discovery.views.CoursesListing', function () {
beforeEach(function () { beforeEach(function () {
jasmine.Clock.useMock(); jasmine.clock().install();
loadFixtures('js/fixtures/discovery.html'); loadFixtures('js/fixtures/discovery.html');
TemplateHelpers.installTemplate('templates/discovery/course_card'); TemplateHelpers.installTemplate('templates/discovery/course_card');
var collection = new Backbone.Collection( var collection = new Backbone.Collection(
...@@ -44,10 +44,14 @@ define([ ...@@ -44,10 +44,14 @@ define([
var mock = { var mock = {
collection: collection, collection: collection,
latest: function () { return this.collection.last(20); } latest: function () { return this.collection.last(20); }
} };
this.view = new CoursesListing({ model: mock }); this.view = new CoursesListing({ model: mock });
}); });
afterEach(function() {
jasmine.clock().uninstall();
});
it('renders search results', function () { it('renders search results', function () {
this.view.render(); this.view.render();
expect($('.courses-listing article').length).toEqual(1); expect($('.courses-listing article').length).toEqual(1);
...@@ -62,13 +66,13 @@ define([ ...@@ -62,13 +66,13 @@ define([
this.view.render(); this.view.render();
window.scroll(0, $(document).height()); window.scroll(0, $(document).height());
$(window).trigger('scroll'); $(window).trigger('scroll');
jasmine.Clock.tick(500); jasmine.clock().tick(500);
expect(this.onNext).toHaveBeenCalled(); expect(this.onNext).toHaveBeenCalled();
// should not be triggered again (while it is loading) // should not be triggered again (while it is loading)
$(window).trigger('scroll'); $(window).trigger('scroll');
jasmine.Clock.tick(500); jasmine.clock().tick(500);
expect(this.onNext.calls.length).toEqual(1); expect(this.onNext.calls.count()).toEqual(1);
}); });
}); });
......
define(['jquery'], function($) {
'use strict';
return function (that) {
that.addMatchers({
toContainText: function (text) {
var trimmedText = $.trim($(this.actual).text());
if (text && $.isFunction(text.test)) {
return text.test(trimmedText);
} else {
return trimmedText.indexOf(text) !== -1;
}
},
toHaveLength: function (number) {
return $(this.actual).length === number;
},
toHaveIndex: function (number) {
return $(this.actual).index() === number;
},
toBeInRange: function (min, max) {
return min <= this.actual && this.actual <= max;
},
toBeFocused: function () {
return $(this.actual)[0] === $(this.actual)[0].ownerDocument.activeElement;
}
});
};
});
define([ define([
'jquery', 'underscore', 'annotator_1.2.9', 'logger', 'js/edxnotes/views/notes_factory', 'js/spec/edxnotes/custom_matchers' 'jquery', 'underscore', 'annotator_1.2.9', 'logger', 'js/edxnotes/views/notes_factory'
], function($, _, Annotator, Logger, NotesFactory, customMatchers) { ], function($, _, Annotator, Logger, NotesFactory) {
'use strict'; 'use strict';
describe('EdxNotes Accessibility Plugin', function() { describe('EdxNotes Accessibility Plugin', function() {
function keyDownEvent (key) { function keyDownEvent (key) {
...@@ -25,7 +25,6 @@ define([ ...@@ -25,7 +25,6 @@ define([
beforeEach(function() { beforeEach(function() {
this.KEY = $.ui.keyCode; this.KEY = $.ui.keyCode;
customMatchers(this);
loadFixtures('js/fixtures/edxnotes/edxnotes_wrapper.html'); loadFixtures('js/fixtures/edxnotes/edxnotes_wrapper.html');
this.annotator = NotesFactory.factory( this.annotator = NotesFactory.factory(
$('div#edx-notes-wrapper-123').get(0), { $('div#edx-notes-wrapper-123').get(0), {
...@@ -45,7 +44,7 @@ define([ ...@@ -45,7 +44,7 @@ define([
describe('destroy', function () { describe('destroy', function () {
it('should unbind all events', function () { it('should unbind all events', function () {
spyOn($.fn, 'off'); spyOn($.fn, 'off');
spyOn(this.annotator, 'unsubscribe').andCallThrough(); spyOn(this.annotator, 'unsubscribe').and.callThrough();
this.plugin.destroy(); this.plugin.destroy();
expect(this.annotator.unsubscribe).toHaveBeenCalledWith( expect(this.annotator.unsubscribe).toHaveBeenCalledWith(
'annotationViewerTextField', this.plugin.addAriaAttributes 'annotationViewerTextField', this.plugin.addAriaAttributes
...@@ -82,7 +81,7 @@ define([ ...@@ -82,7 +81,7 @@ define([
this.annotator.viewer.load([annotation]); this.annotator.viewer.load([annotation]);
note = $('.annotator-note'); note = $('.annotator-note');
expect(note).toExist(); expect(note).toExist();
expect(note).toHaveAttr('tabindex', -1); expect(note).toHaveAttr('tabindex', "-1");
expect(note).toHaveAttr('role', 'note'); expect(note).toHaveAttr('role', 'note');
expect(note).toHaveAttr('class', 'annotator-note'); expect(note).toHaveAttr('class', 'annotator-note');
}); });
...@@ -116,9 +115,9 @@ define([ ...@@ -116,9 +115,9 @@ define([
highlights: [highlight.get(0)] highlights: [highlight.get(0)]
}; };
highlight.data('annotation', annotation); highlight.data('annotation', annotation);
spyOn(this.annotator, 'showViewer').andCallThrough(); spyOn(this.annotator, 'showViewer').and.callThrough();
spyOn(this.annotator.viewer, 'hide').andCallThrough(); spyOn(this.annotator.viewer, 'hide').and.callThrough();
spyOn(this.plugin, 'focusOnGrabber').andCallThrough(); spyOn(this.plugin, 'focusOnGrabber').and.callThrough();
}); });
it('should open the viewer on SPACE keydown and focus on note', function () { it('should open the viewer on SPACE keydown and focus on note', function () {
...@@ -175,7 +174,7 @@ define([ ...@@ -175,7 +174,7 @@ define([
edit= this.annotator.element.find('.annotator-edit').first(); edit= this.annotator.element.find('.annotator-edit').first();
del = this.annotator.element.find('.annotator-delete').first(); del = this.annotator.element.find('.annotator-delete').first();
close = this.annotator.element.find('.annotator-close').first(); close = this.annotator.element.find('.annotator-close').first();
spyOn(this.annotator.viewer, 'hide').andCallThrough(); spyOn(this.annotator.viewer, 'hide').and.callThrough();
}); });
it('should give focus to Note on Listing TAB keydown', function () { it('should give focus to Note on Listing TAB keydown', function () {
...@@ -221,7 +220,7 @@ define([ ...@@ -221,7 +220,7 @@ define([
control.focus(); control.focus();
control.trigger(keyDownEvent(this.KEY.ESCAPE)); control.trigger(keyDownEvent(this.KEY.ESCAPE));
}, this); }, this);
expect(this.annotator.viewer.hide.callCount).toBe(5); expect(this.annotator.viewer.hide.calls.count()).toBe(5);
}); });
}); });
...@@ -243,8 +242,8 @@ define([ ...@@ -243,8 +242,8 @@ define([
tags = annotatorItems.first().next().children('input'); tags = annotatorItems.first().next().children('input');
save = this.annotator.element.find('.annotator-save'); save = this.annotator.element.find('.annotator-save');
cancel = this.annotator.element.find('.annotator-cancel'); cancel = this.annotator.element.find('.annotator-cancel');
spyOn(this.annotator.editor, 'submit').andCallThrough(); spyOn(this.annotator.editor, 'submit').and.callThrough();
spyOn(this.annotator.editor, 'hide').andCallThrough(); spyOn(this.annotator.editor, 'hide').and.callThrough();
}); });
it('should give focus to TextArea on Form TAB keydown', function () { it('should give focus to TextArea on Form TAB keydown', function () {
...@@ -287,7 +286,7 @@ define([ ...@@ -287,7 +286,7 @@ define([
save.focus(); save.focus();
save.trigger(keyDownEvent(this.KEY.ENTER)); save.trigger(keyDownEvent(this.KEY.ENTER));
expect(this.annotator.editor.submit).toHaveBeenCalled(); expect(this.annotator.editor.submit).toHaveBeenCalled();
this.annotator.editor.submit.reset(); this.annotator.editor.submit.calls.reset();
save.focus(); save.focus();
save.trigger(keyDownEvent(this.KEY.SPACE)); save.trigger(keyDownEvent(this.KEY.SPACE));
expect(this.annotator.editor.submit).toHaveBeenCalled(); expect(this.annotator.editor.submit).toHaveBeenCalled();
...@@ -297,7 +296,7 @@ define([ ...@@ -297,7 +296,7 @@ define([
textArea.focus(); textArea.focus();
textArea.trigger(enterMetaKeyEvent()); textArea.trigger(enterMetaKeyEvent());
expect(this.annotator.editor.submit).toHaveBeenCalled(); expect(this.annotator.editor.submit).toHaveBeenCalled();
this.annotator.editor.submit.reset(); this.annotator.editor.submit.calls.reset();
textArea.focus(); textArea.focus();
textArea.trigger(enterControlKeyEvent()); textArea.trigger(enterControlKeyEvent());
expect(this.annotator.editor.submit).toHaveBeenCalled(); expect(this.annotator.editor.submit).toHaveBeenCalled();
...@@ -307,7 +306,7 @@ define([ ...@@ -307,7 +306,7 @@ define([
cancel.focus(); cancel.focus();
cancel.trigger(keyDownEvent(this.KEY.ENTER)); cancel.trigger(keyDownEvent(this.KEY.ENTER));
expect(this.annotator.editor.hide).toHaveBeenCalled(); expect(this.annotator.editor.hide).toHaveBeenCalled();
this.annotator.editor.hide.reset(); this.annotator.editor.hide.calls.reset();
cancel.focus(); cancel.focus();
save.trigger(keyDownEvent(this.KEY.SPACE)); save.trigger(keyDownEvent(this.KEY.SPACE));
expect(this.annotator.editor.hide).toHaveBeenCalled(); expect(this.annotator.editor.hide).toHaveBeenCalled();
...@@ -320,7 +319,7 @@ define([ ...@@ -320,7 +319,7 @@ define([
control.focus(); control.focus();
control.trigger(keyDownEvent(this.KEY.ESCAPE)); control.trigger(keyDownEvent(this.KEY.ESCAPE));
}, this); }, this);
expect(this.annotator.editor.hide.callCount).toBe(3); expect(this.annotator.editor.hide.calls.count()).toBe(3);
}); });
}); });
}); });
......
...@@ -87,10 +87,10 @@ define([ ...@@ -87,10 +87,10 @@ define([
this.mockSubscriber = jasmine.createSpy(); this.mockSubscriber = jasmine.createSpy();
this.annotator.subscribe('annotationCreated', this.mockSubscriber); this.annotator.subscribe('annotationCreated', this.mockSubscriber);
spyOn($.fn, 'position').andReturn(this.mockOffset); spyOn($.fn, 'position').and.returnValue(this.mockOffset);
spyOn(this.annotator, 'createAnnotation').andReturn(this.annotation); spyOn(this.annotator, 'createAnnotation').and.returnValue(this.annotation);
spyOn(this.annotator, 'setupAnnotation').andReturn(this.annotation); spyOn(this.annotator, 'setupAnnotation').and.returnValue(this.annotation);
spyOn(this.annotator, 'getSelectedRanges').andReturn([{}]); spyOn(this.annotator, 'getSelectedRanges').and.returnValue([{}]);
spyOn(this.annotator, 'deleteAnnotation'); spyOn(this.annotator, 'deleteAnnotation');
spyOn(this.annotator, 'showEditor'); spyOn(this.annotator, 'showEditor');
spyOn(Annotator.Util, 'readRangeViaSelection'); spyOn(Annotator.Util, 'readRangeViaSelection');
...@@ -100,7 +100,7 @@ define([ ...@@ -100,7 +100,7 @@ define([
it('should create a new annotation', function () { it('should create a new annotation', function () {
triggerEvent(this.element); triggerEvent(this.element);
expect(this.annotator.createAnnotation.callCount).toBe(1); expect(this.annotator.createAnnotation.calls.count()).toBe(1);
}); });
it('should set up the annotation', function () { it('should set up the annotation', function () {
...@@ -111,25 +111,25 @@ define([ ...@@ -111,25 +111,25 @@ define([
}); });
it('should display the Annotation#editor correctly if the Annotation#adder is hidden', function () { it('should display the Annotation#editor correctly if the Annotation#adder is hidden', function () {
spyOn($.fn, 'is').andReturn(false); spyOn($.fn, 'is').and.returnValue(false);
triggerEvent(this.element); triggerEvent(this.element);
expect($('annotator-hl-temporary').position.callCount).toBe(1); expect($('annotator-hl-temporary').position.calls.count()).toBe(1);
expect(this.annotator.showEditor).toHaveBeenCalledWith( expect(this.annotator.showEditor).toHaveBeenCalledWith(
this.annotation, this.mockOffset this.annotation, this.mockOffset
); );
}); });
it('should display the Annotation#editor in the same place as the Annotation#adder', function () { it('should display the Annotation#editor in the same place as the Annotation#adder', function () {
spyOn($.fn, 'is').andReturn(true); spyOn($.fn, 'is').and.returnValue(true);
triggerEvent(this.element); triggerEvent(this.element);
expect(this.annotator.adder.position.callCount).toBe(1); expect(this.annotator.adder.position.calls.count()).toBe(1);
expect(this.annotator.showEditor).toHaveBeenCalledWith( expect(this.annotator.showEditor).toHaveBeenCalledWith(
this.annotation, this.mockOffset this.annotation, this.mockOffset
); );
}); });
it('should hide the Annotation#adder', function () { it('should hide the Annotation#adder', function () {
spyOn($.fn, 'is').andReturn(true); spyOn($.fn, 'is').and.returnValue(true);
spyOn($.fn, 'hide'); spyOn($.fn, 'hide');
triggerEvent(this.element); triggerEvent(this.element);
expect(this.annotator.adder.hide).toHaveBeenCalled(); expect(this.annotator.adder.hide).toHaveBeenCalled();
...@@ -187,13 +187,13 @@ define([ ...@@ -187,13 +187,13 @@ define([
}); });
it('should do nothing if empty selection', function () { it('should do nothing if empty selection', function () {
this.annotator.getSelectedRanges.andReturn([]); this.annotator.getSelectedRanges.and.returnValue([]);
triggerEvent(this.element); triggerEvent(this.element);
expect(this.annotator.showEditor).not.toHaveBeenCalled(); expect(this.annotator.showEditor).not.toHaveBeenCalled();
}); });
it('should do nothing if selection is in Annotator', function () { it('should do nothing if selection is in Annotator', function () {
spyOn(this.annotator, 'isAnnotator').andReturn(true); spyOn(this.annotator, 'isAnnotator').and.returnValue(true);
triggerEvent(this.element); triggerEvent(this.element);
expect(this.annotator.showEditor).not.toHaveBeenCalled(); expect(this.annotator.showEditor).not.toHaveBeenCalled();
}); });
......
define([ define([
'jquery', 'underscore', 'annotator_1.2.9', 'js/edxnotes/views/notes_factory', 'jquery', 'underscore', 'annotator_1.2.9', 'js/edxnotes/views/notes_factory'
'js/spec/edxnotes/custom_matchers' ], function($, _, Annotator, NotesFactory) {
], function($, _, Annotator, NotesFactory, customMatchers) {
'use strict'; 'use strict';
describe('EdxNotes Scroll Plugin', function() { describe('EdxNotes Scroll Plugin', function() {
var annotators, highlights; var annotators, highlights;
...@@ -19,7 +18,6 @@ define([ ...@@ -19,7 +18,6 @@ define([
} }
beforeEach(function() { beforeEach(function() {
customMatchers(this);
loadFixtures('js/fixtures/edxnotes/edxnotes_wrapper.html'); loadFixtures('js/fixtures/edxnotes/edxnotes_wrapper.html');
annotators = [ annotators = [
NotesFactory.factory($('div#edx-notes-wrapper-123').get(0), { NotesFactory.factory($('div#edx-notes-wrapper-123').get(0), {
...@@ -31,9 +29,9 @@ define([ ...@@ -31,9 +29,9 @@ define([
]; ];
highlights = _.map(annotators, function(annotator) { highlights = _.map(annotators, function(annotator) {
spyOn(annotator, 'onHighlightClick').andCallThrough(); spyOn(annotator, 'onHighlightClick').and.callThrough();
spyOn(annotator, 'onHighlightMouseover').andCallThrough(); spyOn(annotator, 'onHighlightMouseover').and.callThrough();
spyOn(annotator, 'startViewerHideTimer').andCallThrough(); spyOn(annotator, 'startViewerHideTimer').and.callThrough();
return $('<span></span>', { return $('<span></span>', {
'class': 'annotator-hl', 'class': 'annotator-hl',
'tabindex': -1, 'tabindex': -1,
...@@ -41,8 +39,8 @@ define([ ...@@ -41,8 +39,8 @@ define([
}).appendTo(annotator.element); }).appendTo(annotator.element);
}); });
spyOn(annotators[0].plugins.Scroller, 'getIdFromLocationHash').andReturn('abc123'); spyOn(annotators[0].plugins.Scroller, 'getIdFromLocationHash').and.returnValue('abc123');
spyOn($.fn, 'unbind').andCallThrough(); spyOn($.fn, 'unbind').and.callThrough();
}); });
afterEach(function () { afterEach(function () {
...@@ -56,7 +54,7 @@ define([ ...@@ -56,7 +54,7 @@ define([
id: 'abc123', id: 'abc123',
highlights: [highlights[0]] highlights: [highlights[0]]
}]); }]);
annotators[0].onHighlightMouseover.reset(); annotators[0].onHighlightMouseover.calls.reset();
expect(highlights[0]).toBeFocused(); expect(highlights[0]).toBeFocused();
highlights[0].mouseover(); highlights[0].mouseover();
highlights[0].mouseout(); highlights[0].mouseout();
......
define([ define([
'logger', 'js/edxnotes/utils/logger', 'js/spec/edxnotes/custom_matchers' 'logger', 'js/edxnotes/utils/logger'
], function(Logger, NotesLogger, customMatchers) { ], function(Logger, NotesLogger) {
'use strict'; 'use strict';
describe('Edxnotes NotesLogger', function() { describe('Edxnotes NotesLogger', function() {
var getLogger = function(id, mode) { var getLogger = function(id, mode) {
...@@ -11,7 +11,6 @@ define([ ...@@ -11,7 +11,6 @@ define([
spyOn(window.console, 'log'); spyOn(window.console, 'log');
spyOn(window.console, 'error'); spyOn(window.console, 'error');
spyOn(Logger, 'log'); spyOn(Logger, 'log');
customMatchers(this);
}); });
it('keeps a correct history of logs', function() { it('keeps a correct history of logs', function() {
...@@ -94,11 +93,11 @@ define([ ...@@ -94,11 +93,11 @@ define([
it('can use timers', function() { it('can use timers', function() {
var logger = getLogger('id', 1), logs, log; var logger = getLogger('id', 1), logs, log;
spyOn(performance, 'now').andReturn(1); spyOn(performance, 'now').and.returnValue(1);
spyOn(Date, 'now').andReturn(1); spyOn(Date, 'now').and.returnValue(1);
logger.time('timer'); logger.time('timer');
performance.now.andReturn(201); performance.now.and.returnValue(201);
Date.now.andReturn(201); Date.now.and.returnValue(201);
logger.timeEnd('timer'); logger.timeEnd('timer');
logs = logger.getHistory(); logs = logger.getHistory();
......
...@@ -2,10 +2,8 @@ define([ ...@@ -2,10 +2,8 @@ define([
'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers',
'common/js/spec_helpers/template_helpers', 'js/spec/edxnotes/helpers', 'logger', 'common/js/spec_helpers/template_helpers', 'js/spec/edxnotes/helpers', 'logger',
'js/edxnotes/models/note', 'js/edxnotes/views/note_item', 'js/edxnotes/models/note', 'js/edxnotes/views/note_item',
'js/spec/edxnotes/custom_matchers'
], function( ], function(
$, _, AjaxHelpers, TemplateHelpers, Helpers, Logger, NoteModel, NoteItemView, $, _, AjaxHelpers, TemplateHelpers, Helpers, Logger, NoteModel, NoteItemView
customMatchers
) { ) {
'use strict'; 'use strict';
describe('EdxNotes NoteItemView', function() { describe('EdxNotes NoteItemView', function() {
...@@ -27,16 +25,15 @@ define([ ...@@ -27,16 +25,15 @@ define([
}; };
beforeEach(function() { beforeEach(function() {
customMatchers(this);
TemplateHelpers.installTemplate('templates/edxnotes/note-item'); TemplateHelpers.installTemplate('templates/edxnotes/note-item');
spyOn(Logger, 'log').andCallThrough(); spyOn(Logger, 'log').and.callThrough();
}); });
it('can be rendered properly', function() { it('can be rendered properly', function() {
var view = getView(), var view = getView(),
unitLink = view.$('.reference-unit-link').get(0); unitLink = view.$('.reference-unit-link').get(0);
expect(view.$el).toContain('.note-excerpt-more-link'); expect(view.$el).toContainElement('.note-excerpt-more-link');
expect(view.$el).toContainText(Helpers.PRUNED_TEXT); expect(view.$el).toContainText(Helpers.PRUNED_TEXT);
expect(view.$el).toContainText('More'); expect(view.$el).toContainText('More');
view.$('.note-excerpt-more-link').click(); view.$('.note-excerpt-more-link').click();
......
define([ define([
'annotator_1.2.9', 'js/edxnotes/views/notes_factory', 'common/js/spec_helpers/ajax_helpers', 'annotator_1.2.9', 'js/edxnotes/views/notes_factory', 'common/js/spec_helpers/ajax_helpers',
'js/spec/edxnotes/helpers', 'js/spec/edxnotes/custom_matchers' 'js/spec/edxnotes/helpers'
], function(Annotator, NotesFactory, AjaxHelpers, Helpers, customMatchers) { ], function(Annotator, NotesFactory, AjaxHelpers, Helpers) {
'use strict'; 'use strict';
describe('EdxNotes NotesFactory', function() { describe('EdxNotes NotesFactory', function() {
beforeEach(function() { beforeEach(function() {
customMatchers(this);
loadFixtures('js/fixtures/edxnotes/edxnotes_wrapper.html'); loadFixtures('js/fixtures/edxnotes/edxnotes_wrapper.html');
this.wrapper = document.getElementById('edx-notes-wrapper-123'); this.wrapper = document.getElementById('edx-notes-wrapper-123');
}); });
......
define([ define([
'jquery', 'underscore', 'common/js/spec_helpers/template_helpers', 'jquery', 'underscore', 'common/js/spec_helpers/template_helpers',
'common/js/spec_helpers/ajax_helpers', 'js/spec/edxnotes/helpers', 'common/js/spec_helpers/ajax_helpers', 'js/spec/edxnotes/helpers',
'js/edxnotes/views/page_factory', 'js/spec/edxnotes/custom_matchers' 'js/edxnotes/views/page_factory'
], function($, _, TemplateHelpers, AjaxHelpers, Helpers, NotesFactory, customMatchers) { ], function($, _, TemplateHelpers, AjaxHelpers, Helpers, NotesFactory) {
'use strict'; 'use strict';
describe('EdxNotes NotesPage', function() { describe('EdxNotes NotesPage', function() {
var notes = Helpers.getDefaultNotes(); var notes = Helpers.getDefaultNotes();
beforeEach(function() { beforeEach(function() {
customMatchers(this);
loadFixtures('js/fixtures/edxnotes/edxnotes.html'); loadFixtures('js/fixtures/edxnotes/edxnotes.html');
TemplateHelpers.installTemplates([ TemplateHelpers.installTemplates([
'templates/edxnotes/note-item', 'templates/edxnotes/tab-item' 'templates/edxnotes/note-item', 'templates/edxnotes/tab-item'
......
define([ define([
'jquery', 'underscore', 'annotator_1.2.9', 'common/js/spec_helpers/ajax_helpers', 'jquery', 'underscore', 'annotator_1.2.9', 'common/js/spec_helpers/ajax_helpers',
'js/edxnotes/views/notes_visibility_factory', 'js/spec/edxnotes/helpers', 'js/edxnotes/views/notes_visibility_factory', 'js/spec/edxnotes/helpers'
'js/spec/edxnotes/custom_matchers', 'jasmine-jquery'
], function( ], function(
$, _, Annotator, AjaxHelpers, NotesVisibilityFactory, Helpers, customMatchers $, _, Annotator, AjaxHelpers, NotesVisibilityFactory, Helpers
) { ) {
'use strict'; 'use strict';
describe('EdxNotes ToggleNotesFactory', function() { describe('EdxNotes ToggleNotesFactory', function() {
...@@ -17,7 +16,6 @@ define([ ...@@ -17,7 +16,6 @@ define([
}; };
beforeEach(function() { beforeEach(function() {
customMatchers(this);
loadFixtures( loadFixtures(
'js/fixtures/edxnotes/edxnotes_wrapper.html', 'js/fixtures/edxnotes/edxnotes_wrapper.html',
'js/fixtures/edxnotes/toggle_notes.html' 'js/fixtures/edxnotes/toggle_notes.html'
...@@ -32,7 +30,7 @@ define([ ...@@ -32,7 +30,7 @@ define([
this.button = $('.action-toggle-notes'); this.button = $('.action-toggle-notes');
this.label = this.button.find('.utility-control-label'); this.label = this.button.find('.utility-control-label');
this.toggleMessage = $('.action-toggle-message'); this.toggleMessage = $('.action-toggle-message');
spyOn(this.toggleNotes, 'toggleHandler').andCallThrough(); spyOn(this.toggleNotes, 'toggleHandler').and.callThrough();
}); });
afterEach(function () { afterEach(function () {
......
define([ define([
'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers', 'js/edxnotes/views/search_box', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers', 'js/edxnotes/views/search_box',
'js/edxnotes/collections/notes', 'js/spec/edxnotes/custom_matchers', 'js/spec/edxnotes/helpers', 'jasmine-jquery' 'js/edxnotes/collections/notes', 'js/spec/edxnotes/helpers'
], function($, _, AjaxHelpers, SearchBoxView, NotesCollection, customMatchers, Helpers) { ], function($, _, AjaxHelpers, SearchBoxView, NotesCollection, Helpers) {
'use strict'; 'use strict';
describe('EdxNotes SearchBoxView', function() { describe('EdxNotes SearchBoxView', function() {
var getSearchBox, submitForm, assertBoxIsEnabled, assertBoxIsDisabled, searchResponse; var getSearchBox, submitForm, assertBoxIsEnabled, assertBoxIsDisabled, searchResponse;
...@@ -47,7 +47,6 @@ define([ ...@@ -47,7 +47,6 @@ define([
}; };
beforeEach(function () { beforeEach(function () {
customMatchers(this);
loadFixtures('js/fixtures/edxnotes/edxnotes.html'); loadFixtures('js/fixtures/edxnotes/edxnotes.html');
spyOn(Logger, 'log'); spyOn(Logger, 'log');
this.searchBox = getSearchBox(); this.searchBox = getSearchBox();
......
define([ define([
'jquery', 'underscore', 'annotator_1.2.9', 'js/edxnotes/views/notes_factory', 'jasmine-jquery' 'jquery', 'underscore', 'annotator_1.2.9', 'js/edxnotes/views/notes_factory'
], function($, _, Annotator, NotesFactory) { ], function($, _, Annotator, NotesFactory) {
'use strict'; 'use strict';
describe('EdxNotes Shim', function() { describe('EdxNotes Shim', function() {
...@@ -38,11 +38,11 @@ define([ ...@@ -38,11 +38,11 @@ define([
]; ];
_.each(annotators, function(annotator) { _.each(annotators, function(annotator) {
highlights.push($('<span class="annotator-hl" />').appendTo(annotator.element)); highlights.push($('<span class="annotator-hl" />').appendTo(annotator.element));
spyOn(annotator, 'onHighlightClick').andCallThrough(); spyOn(annotator, 'onHighlightClick').and.callThrough();
spyOn(annotator, 'onHighlightMouseover').andCallThrough(); spyOn(annotator, 'onHighlightMouseover').and.callThrough();
spyOn(annotator, 'startViewerHideTimer').andCallThrough(); spyOn(annotator, 'startViewerHideTimer').and.callThrough();
}); });
spyOn($.fn, 'off').andCallThrough(); spyOn($.fn, 'off').and.callThrough();
}); });
afterEach(function () { afterEach(function () {
...@@ -59,9 +59,9 @@ define([ ...@@ -59,9 +59,9 @@ define([
}); });
it('clicking on highlights does not open the viewer when the editor is opened', function() { it('clicking on highlights does not open the viewer when the editor is opened', function() {
spyOn(annotators[1].editor, 'isShown').andReturn(false); spyOn(annotators[1].editor, 'isShown').and.returnValue(false);
highlights[0].click(); highlights[0].click();
annotators[1].editor.isShown.andReturn(true); annotators[1].editor.isShown.and.returnValue(true);
highlights[1].click(); highlights[1].click();
expect($('#edx-notes-wrapper-123 .annotator-viewer')).not.toHaveClass('annotator-hide'); expect($('#edx-notes-wrapper-123 .annotator-viewer')).not.toHaveClass('annotator-hide');
expect($('#edx-notes-wrapper-456 .annotator-viewer')).toHaveClass('annotator-hide'); expect($('#edx-notes-wrapper-456 .annotator-viewer')).toHaveClass('annotator-hide');
...@@ -76,7 +76,7 @@ define([ ...@@ -76,7 +76,7 @@ define([
// in turn calls onHighlightMouseover. // in turn calls onHighlightMouseover.
// To test if onHighlightMouseover is called or not on // To test if onHighlightMouseover is called or not on
// mouseover, we'll have to reset onHighlightMouseover. // mouseover, we'll have to reset onHighlightMouseover.
annotators[0].onHighlightMouseover.reset(); annotators[0].onHighlightMouseover.calls.reset();
// Check that both instances of annotator are frozen // Check that both instances of annotator are frozen
_.invoke(highlights, 'mouseover'); _.invoke(highlights, 'mouseover');
_.invoke(highlights, 'mouseout'); _.invoke(highlights, 'mouseout');
...@@ -86,7 +86,7 @@ define([ ...@@ -86,7 +86,7 @@ define([
it('clicking twice reverts to default behavior', function() { it('clicking twice reverts to default behavior', function() {
highlights[0].click(); highlights[0].click();
$(document).click(); $(document).click();
annotators[0].onHighlightMouseover.reset(); annotators[0].onHighlightMouseover.calls.reset();
// Check that both instances of annotator are unfrozen // Check that both instances of annotator are unfrozen
_.invoke(highlights, 'mouseover'); _.invoke(highlights, 'mouseover');
...@@ -116,7 +116,7 @@ define([ ...@@ -116,7 +116,7 @@ define([
'and unbinds one document click.edxnotes:freeze event handlers', function() { 'and unbinds one document click.edxnotes:freeze event handlers', function() {
// Freeze all instances // Freeze all instances
highlights[0].click(); highlights[0].click();
annotators[0].onHighlightMouseover.reset(); annotators[0].onHighlightMouseover.calls.reset();
// Destroy second instance // Destroy second instance
annotators[1].destroy(); annotators[1].destroy();
...@@ -163,17 +163,17 @@ define([ ...@@ -163,17 +163,17 @@ define([
element: element element: element
}; };
mockViewer.on = jasmine.createSpy().andReturn(mockViewer); mockViewer.on = jasmine.createSpy().and.returnValue(mockViewer);
mockViewer.hide = jasmine.createSpy().andReturn(mockViewer); mockViewer.hide = jasmine.createSpy().and.returnValue(mockViewer);
mockViewer.destroy = jasmine.createSpy().andReturn(mockViewer); mockViewer.destroy = jasmine.createSpy().and.returnValue(mockViewer);
mockViewer.addField = jasmine.createSpy().andCallFake(function (options) { mockViewer.addField = jasmine.createSpy().and.callFake(function (options) {
mockViewer.fields.push(options); mockViewer.fields.push(options);
return mockViewer; return mockViewer;
}); });
spyOn(element, 'bind').andReturn(element); spyOn(element, 'bind').and.returnValue(element);
spyOn(element, 'appendTo').andReturn(element); spyOn(element, 'appendTo').and.returnValue(element);
spyOn(Annotator, 'Viewer').andReturn(mockViewer); spyOn(Annotator, 'Viewer').and.returnValue(mockViewer);
annotators[0]._setupViewer(); annotators[0]._setupViewer();
}); });
...@@ -183,13 +183,13 @@ define([ ...@@ -183,13 +183,13 @@ define([
}); });
it('should hide the annotator on creation', function () { it('should hide the annotator on creation', function () {
expect(mockViewer.hide.callCount).toBe(1); expect(mockViewer.hide.calls.count()).toBe(1);
}); });
it('should setup the default text field', function () { it('should setup the default text field', function () {
var args = mockViewer.addField.mostRecentCall.args[0]; var args = mockViewer.addField.calls.mostRecent().args[0];
expect(mockViewer.addField.callCount).toBe(1); expect(mockViewer.addField.calls.count()).toBe(1);
expect(_.isFunction(args.load)).toBeTruthy(); expect(_.isFunction(args.load)).toBeTruthy();
}); });
......
define([ define([
'jquery', 'common/js/spec_helpers/template_helpers', 'js/edxnotes/collections/tabs', 'jquery', 'common/js/spec_helpers/template_helpers', 'js/edxnotes/collections/tabs',
'js/edxnotes/views/tabs_list', 'js/spec/edxnotes/custom_matchers', 'jasmine-jquery' 'js/edxnotes/views/tabs_list'
], function($, TemplateHelpers, TabsCollection, TabsListView, customMatchers) { ], function($, TemplateHelpers, TabsCollection, TabsListView) {
'use strict'; 'use strict';
describe('EdxNotes TabItemView', function() { describe('EdxNotes TabItemView', function() {
beforeEach(function () { beforeEach(function () {
customMatchers(this);
TemplateHelpers.installTemplate('templates/edxnotes/tab-item'); TemplateHelpers.installTemplate('templates/edxnotes/tab-item');
this.collection = new TabsCollection([ this.collection = new TabsCollection([
{identifier: 'first-item'}, {identifier: 'first-item'},
......
define([ define([
'jquery', 'backbone', 'common/js/spec_helpers/template_helpers', 'js/edxnotes/collections/tabs', 'jquery', 'backbone', 'common/js/spec_helpers/template_helpers', 'js/edxnotes/collections/tabs',
'js/edxnotes/views/tabs_list', 'js/edxnotes/views/tab_view', 'js/edxnotes/views/tabs_list', 'js/edxnotes/views/tab_view'
'js/spec/edxnotes/custom_matchers', 'jasmine-jquery'
], function( ], function(
$, Backbone, TemplateHelpers, TabsCollection, TabsListView, TabView, customMatchers $, Backbone, TemplateHelpers, TabsCollection, TabsListView, TabView
) { ) {
'use strict'; 'use strict';
describe('EdxNotes TabView', function() { describe('EdxNotes TabView', function() {
...@@ -41,7 +40,6 @@ define([ ...@@ -41,7 +40,6 @@ define([
}; };
beforeEach(function () { beforeEach(function () {
customMatchers(this);
loadFixtures('js/fixtures/edxnotes/edxnotes.html'); loadFixtures('js/fixtures/edxnotes/edxnotes.html');
TemplateHelpers.installTemplates([ TemplateHelpers.installTemplates([
'templates/edxnotes/note-item', 'templates/edxnotes/tab-item' 'templates/edxnotes/note-item', 'templates/edxnotes/tab-item'
......
define([ define([
'jquery', 'underscore', 'common/js/spec_helpers/template_helpers', 'js/spec/edxnotes/helpers', 'jquery', 'underscore', 'common/js/spec_helpers/template_helpers', 'js/spec/edxnotes/helpers',
'js/edxnotes/collections/notes', 'js/edxnotes/collections/tabs', 'js/edxnotes/collections/notes', 'js/edxnotes/collections/tabs',
'js/edxnotes/views/tabs/course_structure', 'js/spec/edxnotes/custom_matchers', 'js/edxnotes/views/tabs/course_structure'
'jasmine-jquery'
], function( ], function(
$, _, TemplateHelpers, Helpers, NotesCollection, TabsCollection, CourseStructureView, $, _, TemplateHelpers, Helpers, NotesCollection, TabsCollection, CourseStructureView
customMatchers
) { ) {
'use strict'; 'use strict';
describe('EdxNotes CourseStructureView', function() { describe('EdxNotes CourseStructureView', function() {
...@@ -34,7 +32,6 @@ define([ ...@@ -34,7 +32,6 @@ define([
}; };
beforeEach(function () { beforeEach(function () {
customMatchers(this);
loadFixtures('js/fixtures/edxnotes/edxnotes.html'); loadFixtures('js/fixtures/edxnotes/edxnotes.html');
TemplateHelpers.installTemplates([ TemplateHelpers.installTemplates([
'templates/edxnotes/note-item', 'templates/edxnotes/tab-item' 'templates/edxnotes/note-item', 'templates/edxnotes/tab-item'
......
define([ define([
'jquery', 'common/js/spec_helpers/template_helpers', 'common/js/spec_helpers/ajax_helpers', 'jquery', 'common/js/spec_helpers/template_helpers', 'common/js/spec_helpers/ajax_helpers',
'js/edxnotes/collections/notes', 'js/edxnotes/collections/tabs', 'js/edxnotes/views/tabs/recent_activity', 'js/edxnotes/collections/notes', 'js/edxnotes/collections/tabs', 'js/edxnotes/views/tabs/recent_activity',
'js/spec/edxnotes/custom_matchers', 'js/spec/edxnotes/helpers', 'jasmine-jquery' 'js/spec/edxnotes/helpers'
], function( ], function(
$, TemplateHelpers, AjaxHelpers, NotesCollection, TabsCollection, RecentActivityView, customMatchers, Helpers $, TemplateHelpers, AjaxHelpers, NotesCollection, TabsCollection, RecentActivityView, Helpers
) { ) {
'use strict'; 'use strict';
describe('EdxNotes RecentActivityView', function() { describe('EdxNotes RecentActivityView', function() {
...@@ -64,7 +64,6 @@ define([ ...@@ -64,7 +64,6 @@ define([
recentActivityTabId = '#recent-panel'; recentActivityTabId = '#recent-panel';
beforeEach(function () { beforeEach(function () {
customMatchers(this);
loadFixtures('js/fixtures/edxnotes/edxnotes.html'); loadFixtures('js/fixtures/edxnotes/edxnotes.html');
TemplateHelpers.installTemplates([ TemplateHelpers.installTemplates([
'templates/edxnotes/note-item', 'templates/edxnotes/tab-item' 'templates/edxnotes/note-item', 'templates/edxnotes/tab-item'
......
define([ define([
'jquery', 'underscore', 'common/js/spec_helpers/template_helpers', 'common/js/spec_helpers/ajax_helpers', 'jquery', 'underscore', 'common/js/spec_helpers/template_helpers', 'common/js/spec_helpers/ajax_helpers',
'logger', 'js/edxnotes/collections/tabs', 'js/edxnotes/views/tabs/search_results', 'logger', 'js/edxnotes/collections/tabs', 'js/edxnotes/views/tabs/search_results',
'js/spec/edxnotes/custom_matchers', 'js/spec/edxnotes/helpers', 'jasmine-jquery' 'js/spec/edxnotes/helpers'
], function( ], function(
$, _, TemplateHelpers, AjaxHelpers, Logger, TabsCollection, SearchResultsView, $, _, TemplateHelpers, AjaxHelpers, Logger, TabsCollection, SearchResultsView, Helpers
customMatchers, Helpers
) { ) {
'use strict'; 'use strict';
describe('EdxNotes SearchResultsView', function() { describe('EdxNotes SearchResultsView', function() {
...@@ -69,7 +68,6 @@ define([ ...@@ -69,7 +68,6 @@ define([
searchResultsTabId = "#search-results-panel"; searchResultsTabId = "#search-results-panel";
beforeEach(function () { beforeEach(function () {
customMatchers(this);
loadFixtures('js/fixtures/edxnotes/edxnotes.html'); loadFixtures('js/fixtures/edxnotes/edxnotes.html');
TemplateHelpers.installTemplates([ TemplateHelpers.installTemplates([
'templates/edxnotes/note-item', 'templates/edxnotes/tab-item' 'templates/edxnotes/note-item', 'templates/edxnotes/tab-item'
...@@ -146,7 +144,7 @@ define([ ...@@ -146,7 +144,7 @@ define([
it('can clear search results if tab is closed', function () { it('can clear search results if tab is closed', function () {
var view = getView(this.tabsCollection), var view = getView(this.tabsCollection),
requests = AjaxHelpers.requests(this); requests = AjaxHelpers.requests(this);
spyOn(view.searchBox, 'clearInput').andCallThrough(); spyOn(view.searchBox, 'clearInput').and.callThrough();
submitForm(view.searchBox, 'test_query'); submitForm(view.searchBox, 'test_query');
Helpers.respondToRequest(requests, responseJson, true); Helpers.respondToRequest(requests, responseJson, true);
......
define([ define([
'jquery', 'underscore', 'common/js/spec_helpers/template_helpers', 'js/spec/edxnotes/helpers', 'jquery', 'underscore', 'common/js/spec_helpers/template_helpers', 'js/spec/edxnotes/helpers',
'js/edxnotes/collections/notes', 'js/edxnotes/collections/tabs', 'js/edxnotes/collections/notes', 'js/edxnotes/collections/tabs',
'js/edxnotes/views/tabs/tags', 'js/spec/edxnotes/custom_matchers', 'js/edxnotes/views/tabs/tags'
'jasmine-jquery'
], function( ], function(
$, _, TemplateHelpers, Helpers, NotesCollection, TabsCollection, TagsView, $, _, TemplateHelpers, Helpers, NotesCollection, TabsCollection, TagsView
customMatchers
) { ) {
'use strict'; 'use strict';
describe('EdxNotes TagsView', function() { describe('EdxNotes TagsView', function() {
...@@ -38,7 +36,6 @@ define([ ...@@ -38,7 +36,6 @@ define([
}; };
beforeEach(function () { beforeEach(function () {
customMatchers(this);
loadFixtures('js/fixtures/edxnotes/edxnotes.html'); loadFixtures('js/fixtures/edxnotes/edxnotes.html');
TemplateHelpers.installTemplates([ TemplateHelpers.installTemplates([
'templates/edxnotes/note-item', 'templates/edxnotes/tab-item' 'templates/edxnotes/note-item', 'templates/edxnotes/tab-item'
......
define([ define([
'jquery', 'common/js/spec_helpers/template_helpers', 'js/edxnotes/collections/tabs', 'jquery', 'common/js/spec_helpers/template_helpers', 'js/edxnotes/collections/tabs',
'js/edxnotes/views/tabs_list', 'js/spec/edxnotes/custom_matchers', 'jasmine-jquery' 'js/edxnotes/views/tabs_list'
], function($, TemplateHelpers, TabsCollection, TabsListView, customMatchers) { ], function($, TemplateHelpers, TabsCollection, TabsListView) {
'use strict'; 'use strict';
describe('EdxNotes TabsListView', function() { describe('EdxNotes TabsListView', function() {
beforeEach(function () { beforeEach(function () {
customMatchers(this);
TemplateHelpers.installTemplate('templates/edxnotes/tab-item'); TemplateHelpers.installTemplate('templates/edxnotes/tab-item');
this.collection = new TabsCollection([ this.collection = new TabsCollection([
{identifier: 'first-item'}, {identifier: 'first-item'},
......
define([ define([
'annotator_1.2.9', 'js/edxnotes/views/visibility_decorator', 'annotator_1.2.9', 'js/edxnotes/views/visibility_decorator',
'js/spec/edxnotes/helpers', 'js/spec/edxnotes/custom_matchers' 'js/spec/edxnotes/helpers'
], function(Annotator, VisibilityDecorator, Helpers, customMatchers) { ], function(Annotator, VisibilityDecorator, Helpers) {
'use strict'; 'use strict';
describe('EdxNotes VisibilityDecorator', function() { describe('EdxNotes VisibilityDecorator', function() {
var params = { var params = {
...@@ -14,7 +14,6 @@ define([ ...@@ -14,7 +14,6 @@ define([
}; };
beforeEach(function() { beforeEach(function() {
customMatchers(this);
loadFixtures('js/fixtures/edxnotes/edxnotes_wrapper.html'); loadFixtures('js/fixtures/edxnotes/edxnotes_wrapper.html');
this.wrapper = document.getElementById('edx-notes-wrapper-123'); this.wrapper = document.getElementById('edx-notes-wrapper-123');
}); });
......
...@@ -108,7 +108,7 @@ define([ ...@@ -108,7 +108,7 @@ define([
view.$('#financial-assistance-course').val(selectValue); view.$('#financial-assistance-course').val(selectValue);
view.$('#financial-assistance-income').val(1312); view.$('#financial-assistance-income').val(1312);
view.$('textarea').html('w'.repeat(801)); view.$('textarea').html(Array(802).join("w"));
}; };
validSubmission = function() { validSubmission = function() {
......
...@@ -31,7 +31,7 @@ define([ ...@@ -31,7 +31,7 @@ define([
it('bind the ajax call and the result will be success', function() { it('bind the ajax call and the result will be success', function() {
var submitCallback; var submitCallback;
spyOn($, "ajax").andCallFake(function(params) { spyOn($, "ajax").and.callFake(function(params) {
params.success({ params.success({
row_errors: {}, row_errors: {},
general_errors: [], general_errors: [],
...@@ -41,7 +41,7 @@ define([ ...@@ -41,7 +41,7 @@ define([
always: function() {} always: function() {}
}; };
}); });
submitCallback = jasmine.createSpy().andReturn(); submitCallback = jasmine.createSpy().and.returnValue();
this.view.$el.find(SELECTORS.bulk_white_list_exception_form).submit(submitCallback); this.view.$el.find(SELECTORS.bulk_white_list_exception_form).submit(submitCallback);
this.view.$el.find(SELECTORS.upload_csv_button).click(); this.view.$el.find(SELECTORS.upload_csv_button).click();
expect($(SELECTORS.bulk_exception_results).text()).toContain('1 learner is successfully added to the ' + expect($(SELECTORS.bulk_exception_results).text()).toContain('1 learner is successfully added to the ' +
...@@ -50,7 +50,7 @@ define([ ...@@ -50,7 +50,7 @@ define([
it('bind the ajax call and the result will be general error', function() { it('bind the ajax call and the result will be general error', function() {
var submitCallback; var submitCallback;
spyOn($, "ajax").andCallFake(function(params) { spyOn($, "ajax").and.callFake(function(params) {
params.success({ params.success({
row_errors: {}, row_errors: {},
general_errors: ["File is not attached."], general_errors: ["File is not attached."],
...@@ -60,7 +60,7 @@ define([ ...@@ -60,7 +60,7 @@ define([
always: function() {} always: function() {}
}; };
}); });
submitCallback = jasmine.createSpy().andReturn(); submitCallback = jasmine.createSpy().and.returnValue();
this.view.$el.find(SELECTORS.bulk_white_list_exception_form).submit(submitCallback); this.view.$el.find(SELECTORS.bulk_white_list_exception_form).submit(submitCallback);
this.view.$el.find(SELECTORS.upload_csv_button).click(); this.view.$el.find(SELECTORS.upload_csv_button).click();
expect($(SELECTORS.bulk_exception_results).text()).toContain('File is not attached.'); expect($(SELECTORS.bulk_exception_results).text()).toContain('File is not attached.');
...@@ -68,7 +68,7 @@ define([ ...@@ -68,7 +68,7 @@ define([
it('bind the ajax call and the result will be singular form of row errors', function() { it('bind the ajax call and the result will be singular form of row errors', function() {
var submitCallback; var submitCallback;
spyOn($, "ajax").andCallFake(function(params) { spyOn($, "ajax").and.callFake(function(params) {
params.success({ params.success({
general_errors: [], general_errors: [],
row_errors: { row_errors: {
...@@ -83,7 +83,7 @@ define([ ...@@ -83,7 +83,7 @@ define([
always: function() {} always: function() {}
}; };
}); });
submitCallback = jasmine.createSpy().andReturn(); submitCallback = jasmine.createSpy().and.returnValue();
this.view.$el.find(SELECTORS.bulk_white_list_exception_form).submit(submitCallback); this.view.$el.find(SELECTORS.bulk_white_list_exception_form).submit(submitCallback);
this.view.$el.find(SELECTORS.upload_csv_button).click(); this.view.$el.find(SELECTORS.upload_csv_button).click();
expect($(SELECTORS.bulk_exception_results).text()).toContain('1 record is not in correct format'); expect($(SELECTORS.bulk_exception_results).text()).toContain('1 record is not in correct format');
...@@ -95,7 +95,7 @@ define([ ...@@ -95,7 +95,7 @@ define([
it('bind the ajax call and the result will be plural form of row errors', function() { it('bind the ajax call and the result will be plural form of row errors', function() {
var submitCallback; var submitCallback;
spyOn($, "ajax").andCallFake(function(params) { spyOn($, "ajax").and.callFake(function(params) {
params.success({ params.success({
general_errors: [], general_errors: [],
row_errors: { row_errors: {
...@@ -110,7 +110,7 @@ define([ ...@@ -110,7 +110,7 @@ define([
always: function() {} always: function() {}
}; };
}); });
submitCallback = jasmine.createSpy().andReturn(); submitCallback = jasmine.createSpy().and.returnValue();
this.view.$el.find(SELECTORS.bulk_white_list_exception_form).submit(submitCallback); this.view.$el.find(SELECTORS.bulk_white_list_exception_form).submit(submitCallback);
this.view.$el.find(SELECTORS.upload_csv_button).click(); this.view.$el.find(SELECTORS.upload_csv_button).click();
expect($(SELECTORS.bulk_exception_results).text()).toContain('2 records are not in correct format'); expect($(SELECTORS.bulk_exception_results).text()).toContain('2 records are not in correct format');
...@@ -122,7 +122,7 @@ define([ ...@@ -122,7 +122,7 @@ define([
it('toggle message details', function() { it('toggle message details', function() {
var submitCallback; var submitCallback;
spyOn($, "ajax").andCallFake(function(params) { spyOn($, "ajax").and.callFake(function(params) {
params.success({ params.success({
row_errors: {}, row_errors: {},
general_errors: [], general_errors: [],
...@@ -132,7 +132,7 @@ define([ ...@@ -132,7 +132,7 @@ define([
always: function() {} always: function() {}
}; };
}); });
submitCallback = jasmine.createSpy().andReturn(); submitCallback = jasmine.createSpy().and.returnValue();
this.view.$el.find(SELECTORS.bulk_white_list_exception_form).submit(submitCallback); this.view.$el.find(SELECTORS.bulk_white_list_exception_form).submit(submitCallback);
this.view.$el.find(SELECTORS.upload_csv_button).click(); this.view.$el.find(SELECTORS.upload_csv_button).click();
expect(this.view.$el.find("div.message > .successfully-added")).toBeHidden(); expect(this.view.$el.find("div.message > .successfully-added")).toBeHidden();
......
...@@ -65,21 +65,21 @@ define([ ...@@ -65,21 +65,21 @@ define([
}); });
it("does not regenerate certificates if user cancels operation in confirm popup", function() { it("does not regenerate certificates if user cancels operation in confirm popup", function() {
spyOn(window, 'confirm').andReturn(false); spyOn(window, 'confirm').and.returnValue(false);
$regenerate_certificates_button.click(); $regenerate_certificates_button.click();
expect(window.confirm).toHaveBeenCalled(); expect(window.confirm).toHaveBeenCalled();
AjaxHelpers.expectNoRequests(requests); AjaxHelpers.expectNoRequests(requests);
}); });
it("sends regenerate certificates request if user accepts operation in confirm popup", function() { it("sends regenerate certificates request if user accepts operation in confirm popup", function() {
spyOn(window, 'confirm').andReturn(true); spyOn(window, 'confirm').and.returnValue(true);
$regenerate_certificates_button.click(); $regenerate_certificates_button.click();
expect(window.confirm).toHaveBeenCalled(); expect(window.confirm).toHaveBeenCalled();
AjaxHelpers.expectRequest(requests, 'POST', expected.url); AjaxHelpers.expectRequest(requests, 'POST', expected.url);
}); });
it("sends regenerate certificates request with selected certificate statuses", function() { it("sends regenerate certificates request with selected certificate statuses", function() {
spyOn(window, 'confirm').andReturn(true); spyOn(window, 'confirm').and.returnValue(true);
select_options(expected.selected_statuses); select_options(expected.selected_statuses);
...@@ -88,7 +88,7 @@ define([ ...@@ -88,7 +88,7 @@ define([
}); });
it("displays error message in case of server side error", function() { it("displays error message in case of server side error", function() {
spyOn(window, 'confirm').andReturn(true); spyOn(window, 'confirm').and.returnValue(true);
select_options(expected.selected_statuses); select_options(expected.selected_statuses);
$regenerate_certificates_button.click(); $regenerate_certificates_button.click();
...@@ -97,7 +97,7 @@ define([ ...@@ -97,7 +97,7 @@ define([
}); });
it("displays error message returned by the server in case of unsuccessful request", function() { it("displays error message returned by the server in case of unsuccessful request", function() {
spyOn(window, 'confirm').andReturn(true); spyOn(window, 'confirm').and.returnValue(true);
select_options(expected.selected_statuses); select_options(expected.selected_statuses);
$regenerate_certificates_button.click(); $regenerate_certificates_button.click();
...@@ -106,7 +106,7 @@ define([ ...@@ -106,7 +106,7 @@ define([
}); });
it("displays success message returned by the server in case of successful request", function() { it("displays success message returned by the server in case of successful request", function() {
spyOn(window, 'confirm').andReturn(true); spyOn(window, 'confirm').and.returnValue(true);
select_options(expected.selected_statuses); select_options(expected.selected_statuses);
$regenerate_certificates_button.click(); $regenerate_certificates_button.click();
......
...@@ -24,7 +24,7 @@ define(['backbone', 'jquery', 'js/instructor_dashboard/ecommerce'], ...@@ -24,7 +24,7 @@ define(['backbone', 'jquery', 'js/instructor_dashboard/ecommerce'],
var target = expiryCouponView.$el.find('input[type="checkbox"]'); var target = expiryCouponView.$el.find('input[type="checkbox"]');
target.attr("checked","checked"); target.attr("checked","checked");
target.click(); target.click();
expect(expiryCouponView.$el.find('#coupon_expiration_date')).toHaveAttr('style','display: inline;'); expect(expiryCouponView.$el.find('#coupon_expiration_date').is(':visible')).toBe(true);
}); });
it("hides the input field when the checkbox is unchecked", function () { it("hides the input field when the checkbox is unchecked", function () {
......
...@@ -17,7 +17,7 @@ define(['jquery', 'coffee/src/instructor_dashboard/student_admin', 'common/js/sp ...@@ -17,7 +17,7 @@ define(['jquery', 'coffee/src/instructor_dashboard/student_admin', 'common/js/sp
dashboard_api_url = '/courses/PU/FSc/2014_T4/instructor/api'; dashboard_api_url = '/courses/PU/FSc/2014_T4/instructor/api';
unique_student_identifier = "test@example.com"; unique_student_identifier = "test@example.com";
alert_msg = ''; alert_msg = '';
spyOn(window, 'alert').andCallFake(function(message) { spyOn(window, 'alert').and.callFake(function(message) {
alert_msg = message; alert_msg = message;
}); });
......
...@@ -47,7 +47,8 @@ ...@@ -47,7 +47,8 @@
'squire': 'xmodule_js/common_static/js/vendor/Squire', 'squire': 'xmodule_js/common_static/js/vendor/Squire',
'jasmine-imagediff': 'xmodule_js/common_static/js/vendor/jasmine-imagediff', 'jasmine-imagediff': 'xmodule_js/common_static/js/vendor/jasmine-imagediff',
'jasmine-stealth': 'xmodule_js/common_static/js/vendor/jasmine-stealth', 'jasmine-stealth': 'xmodule_js/common_static/js/vendor/jasmine-stealth',
'jasmine-waituntil': 'xmodule_js/common_static/js/vendor/jasmine-waituntil', 'jasmine-waituntil': 'xmodule_js/common_static/js/libs/jasmine-waituntil',
'jasmine-extensions': 'xmodule_js/common_static/js/libs/jasmine-extensions',
'draggabilly': 'xmodule_js/common_static/js/vendor/draggabilly.pkgd', 'draggabilly': 'xmodule_js/common_static/js/vendor/draggabilly.pkgd',
'domReady': 'xmodule_js/common_static/js/vendor/domReady', 'domReady': 'xmodule_js/common_static/js/vendor/domReady',
'mathjax': '//cdn.mathjax.org/mathjax/2.6-latest/MathJax.js?config=TeX-MML-AM_SVG&delayStartupUntil=configured', // jshint ignore:line 'mathjax': '//cdn.mathjax.org/mathjax/2.6-latest/MathJax.js?config=TeX-MML-AM_SVG&delayStartupUntil=configured', // jshint ignore:line
...@@ -104,8 +105,8 @@ ...@@ -104,8 +105,8 @@
// Common edx utils // Common edx utils
'common/js/utils/edx.utils.validate': 'xmodule_js/common_static/common/js/utils/edx.utils.validate', 'common/js/utils/edx.utils.validate': 'xmodule_js/common_static/common/js/utils/edx.utils.validate',
'slick.grid': 'xmodule_js/common_static/js/vendor/slick.grid', 'slick.core': 'xmodule_js/common_static/js/vendor/slick.core',
'slick.core': 'xmodule_js/common_static/js/vendor/slick.core' 'slick.grid': 'xmodule_js/common_static/js/vendor/slick.grid'
}, },
shim: { shim: {
'gettext': { 'gettext': {
...@@ -265,6 +266,9 @@ ...@@ -265,6 +266,9 @@
'jasmine-waituntil': { 'jasmine-waituntil': {
deps: ['jquery'] deps: ['jquery']
}, },
'jasmine-extensions': {
deps: ['jquery']
},
'xblock/core': { 'xblock/core': {
exports: 'XBlock', exports: 'XBlock',
deps: ['jquery', 'jquery.immediateDescendents'] deps: ['jquery', 'jquery.immediateDescendents']
...@@ -362,11 +366,18 @@ ...@@ -362,11 +366,18 @@
deps: [ 'jquery', 'underscore', 'underscore.string', 'backbone', 'gettext' ], deps: [ 'jquery', 'underscore', 'underscore.string', 'backbone', 'gettext' ],
init: function() { init: function() {
// Set global variables that the payment code is expecting to be defined // Set global variables that the payment code is expecting to be defined
window._ = require('underscore'); require([
window._.str = require('underscore.string'); 'underscore',
window.edx = edx || {}; 'underscore.string',
window.edx.HtmlUtils = require('edx-ui-toolkit/js/utils/html-utils'); 'edx-ui-toolkit/js/utils/html-utils',
window.edx.StringUtils = require('edx-ui-toolkit/js/utils/string-utils'); 'edx-ui-toolkit/js/utils/string-utils'
], function (_, str, HtmlUtils, StringUtils) {
window._ = _;
window._.str = str;
window.edx = edx || {};
window.edx.HtmlUtils = HtmlUtils;
window.edx.StringUtils = StringUtils;
});
} }
}, },
'js/verify_student/views/intro_step_view': { 'js/verify_student/views/intro_step_view': {
...@@ -491,8 +502,10 @@ ...@@ -491,8 +502,10 @@
exports: 'DiscussionUtil', exports: 'DiscussionUtil',
init: function() { init: function() {
// Set global variables that the discussion code is expecting to be defined // Set global variables that the discussion code is expecting to be defined
window.Backbone = require('backbone'); require(['backbone', 'URI'], function (Backbone, URI) {
window.URI = require('URI'); window.Backbone = Backbone;
window.URI = URI;
});
} }
}, },
'xmodule_js/common_static/coffee/src/discussion/content': { 'xmodule_js/common_static/coffee/src/discussion/content': {
...@@ -546,13 +559,15 @@ ...@@ -546,13 +559,15 @@
}, },
'xmodule_js/common_static/coffee/src/discussion/views/discussion_thread_show_view': { 'xmodule_js/common_static/coffee/src/discussion/views/discussion_thread_show_view': {
deps: [ deps: [
'xmodule_js/common_static/coffee/src/discussion/utils' 'xmodule_js/common_static/coffee/src/discussion/utils',
'xmodule_js/common_static/coffee/src/discussion/views/discussion_content_view'
], ],
exports: 'DiscussionThreadShowView' exports: 'DiscussionThreadShowView'
}, },
'xmodule_js/common_static/coffee/src/discussion/views/discussion_thread_view': { 'xmodule_js/common_static/coffee/src/discussion/views/discussion_thread_view': {
deps: [ deps: [
'xmodule_js/common_static/coffee/src/discussion/utils' 'xmodule_js/common_static/coffee/src/discussion/utils',
'xmodule_js/common_static/coffee/src/discussion/views/discussion_content_view'
], ],
exports: 'DiscussionThreadView' exports: 'DiscussionThreadView'
}, },
......
...@@ -15,7 +15,7 @@ define(['jquery', 'js/utils/navigation'], function($) { ...@@ -15,7 +15,7 @@ define(['jquery', 'js/utils/navigation'], function($) {
chapterMenu = accordion.children('.chapter-content-container').children('.chapter-menu'); chapterMenu = accordion.children('.chapter-content-container').children('.chapter-menu');
this.KEY = $.ui.keyCode; this.KEY = $.ui.keyCode;
spyOn($.fn, 'focus').andCallThrough(); spyOn($.fn, 'focus').and.callThrough();
edx.util.navigation.init(); edx.util.navigation.init();
}); });
......
...@@ -77,14 +77,14 @@ define([ ...@@ -77,14 +77,14 @@ define([
var collection = new SearchCollection([]); var collection = new SearchCollection([]);
spyOn($, 'ajax'); spyOn($, 'ajax');
collection.performSearch('search string'); collection.performSearch('search string');
expect($.ajax.mostRecentCall.args[0].url).toEqual('/search/'); expect($.ajax.calls.mostRecent().args[0].url).toEqual('/search/');
}); });
it('sends a request with course ID', function () { it('sends a request with course ID', function () {
var collection = new SearchCollection([], { courseId: 'edx101' }); var collection = new SearchCollection([], { courseId: 'edx101' });
spyOn($, 'ajax'); spyOn($, 'ajax');
collection.performSearch('search string'); collection.performSearch('search string');
expect($.ajax.mostRecentCall.args[0].url).toEqual('/search/edx101'); expect($.ajax.calls.mostRecent().args[0].url).toEqual('/search/edx101');
}); });
it('sends a request and parses the json result', function () { it('sends a request and parses the json result', function () {
...@@ -139,10 +139,10 @@ define([ ...@@ -139,10 +139,10 @@ define([
AjaxHelpers.respondWithJson(requests, response); AjaxHelpers.respondWithJson(requests, response);
spyOn($, 'ajax'); spyOn($, 'ajax');
this.collection.loadNextPage(); this.collection.loadNextPage();
expect($.ajax.mostRecentCall.args[0].url).toEqual(this.collection.url); expect($.ajax.calls.mostRecent().args[0].url).toEqual(this.collection.url);
expect($.ajax.mostRecentCall.args[0].data.search_string).toEqual(searchString); expect($.ajax.calls.mostRecent().args[0].data.search_string).toEqual(searchString);
expect($.ajax.mostRecentCall.args[0].data.page_size).toEqual(this.collection.pageSize); expect($.ajax.calls.mostRecent().args[0].data.page_size).toEqual(this.collection.pageSize);
expect($.ajax.mostRecentCall.args[0].data.page_index).toEqual(2); expect($.ajax.calls.mostRecent().args[0].data.page_index).toEqual(2);
}); });
it('has next page', function () { it('has next page', function () {
...@@ -164,18 +164,18 @@ define([ ...@@ -164,18 +164,18 @@ define([
this.collection.performSearch('new search'); this.collection.performSearch('new search');
AjaxHelpers.skipResetRequest(requests); AjaxHelpers.skipResetRequest(requests);
AjaxHelpers.respondWithJson(requests, response); AjaxHelpers.respondWithJson(requests, response);
expect(this.onSearch.calls.length).toEqual(1); expect(this.onSearch.calls.count()).toEqual(1);
this.collection.performSearch('old search'); this.collection.performSearch('old search');
this.collection.cancelSearch(); this.collection.cancelSearch();
AjaxHelpers.skipResetRequest(requests); AjaxHelpers.skipResetRequest(requests);
expect(this.onSearch.calls.length).toEqual(1); expect(this.onSearch.calls.count()).toEqual(1);
this.collection.loadNextPage(); this.collection.loadNextPage();
this.collection.loadNextPage(); this.collection.loadNextPage();
AjaxHelpers.skipResetRequest(requests); AjaxHelpers.skipResetRequest(requests);
AjaxHelpers.respondWithJson(requests, response); AjaxHelpers.respondWithJson(requests, response);
expect(this.onNext.calls.length).toEqual(1); expect(this.onNext.calls.count()).toEqual(1);
}); });
describe('reset state', function () { describe('reset state', function () {
...@@ -261,7 +261,7 @@ define([ ...@@ -261,7 +261,7 @@ define([
function rendersItem() { function rendersItem() {
expect(this.item.$el).toHaveAttr('role', 'region'); expect(this.item.$el).toHaveAttr('role', 'region');
expect(this.item.$el).toHaveAttr('aria-label', 'search result'); expect(this.item.$el).toHaveAttr('aria-label', 'search result');
expect(this.item.$el).toContain('a[href="' + this.model.get('url') + '"]'); expect(this.item.$el).toContainElement('a[href="' + this.model.get('url') + '"]');
expect(this.item.$el.find('.result-type')).toContainHtml(this.model.get('content_type')); expect(this.item.$el.find('.result-type')).toContainHtml(this.model.get('content_type'));
expect(this.item.$el.find('.result-excerpt')).toContainHtml(this.model.get('excerpt')); expect(this.item.$el.find('.result-excerpt')).toContainHtml(this.model.get('excerpt'));
expect(this.item.$el.find('.result-location')).toContainHtml('section ▸ subsection ▸ unit'); expect(this.item.$el.find('.result-location')).toContainHtml('section ▸ subsection ▸ unit');
...@@ -270,7 +270,7 @@ define([ ...@@ -270,7 +270,7 @@ define([
function rendersSequentialItem() { function rendersSequentialItem() {
expect(this.seqItem.$el).toHaveAttr('role', 'region'); expect(this.seqItem.$el).toHaveAttr('role', 'region');
expect(this.seqItem.$el).toHaveAttr('aria-label', 'search result'); expect(this.seqItem.$el).toHaveAttr('aria-label', 'search result');
expect(this.seqItem.$el).toContain('a[href="' + this.seqModel.get('url') + '"]'); expect(this.seqItem.$el).toContainElement('a[href="' + this.seqModel.get('url') + '"]');
expect(this.seqItem.$el.find('.result-type')).toBeEmpty(); expect(this.seqItem.$el.find('.result-type')).toBeEmpty();
expect(this.seqItem.$el.find('.result-excerpt')).toBeEmpty(); expect(this.seqItem.$el.find('.result-excerpt')).toBeEmpty();
expect(this.seqItem.$el.find('.result-location')).toContainHtml('section ▸ subsection'); expect(this.seqItem.$el.find('.result-location')).toContainHtml('section ▸ subsection');
...@@ -280,8 +280,8 @@ define([ ...@@ -280,8 +280,8 @@ define([
this.model.collection = new SearchCollection([this.model], { course_id: 'edx101' }); this.model.collection = new SearchCollection([this.model], { course_id: 'edx101' });
this.item.render(); this.item.render();
// Mock the redirect call // Mock the redirect call
spyOn(this.item, 'redirect').andCallFake( function() {} ); spyOn(this.item, 'redirect').and.callFake( function() {} );
spyOn(Logger, 'log').andReturn($.Deferred().resolve()); spyOn(Logger, 'log').and.returnValue($.Deferred().resolve());
this.item.$el.find('a').trigger('click'); this.item.$el.find('a').trigger('click');
expect(this.item.redirect).toHaveBeenCalled(); expect(this.item.redirect).toHaveBeenCalled();
this.item.$el.trigger('click'); this.item.$el.trigger('click');
...@@ -498,7 +498,6 @@ define([ ...@@ -498,7 +498,6 @@ define([
'templates/search/dashboard_search_item', 'templates/search/dashboard_search_item',
'templates/search/course_search_results', 'templates/search/course_search_results',
'templates/search/dashboard_search_results', 'templates/search/dashboard_search_results',
'templates/search/search_list',
'templates/search/search_loading', 'templates/search/search_loading',
'templates/search/search_error' 'templates/search/search_error'
]); ]);
...@@ -601,9 +600,9 @@ define([ ...@@ -601,9 +600,9 @@ define([
function updatesNavigationHistory () { function updatesNavigationHistory () {
$('.search-field').val('edx'); $('.search-field').val('edx');
$('.search-button').trigger('click'); $('.search-button').trigger('click');
expect(Backbone.history.navigate.calls[0].args).toContain('search/edx'); expect(Backbone.history.navigate.calls.mostRecent().args[0]).toContain('search/edx');
$('.cancel-button').trigger('click'); $('.cancel-button').trigger('click');
expect(Backbone.history.navigate.calls[1].args).toContain(''); expect(Backbone.history.navigate.calls.argsFor(1)[0]).toBe('');
} }
function cancelsSearchRequest () { function cancelsSearchRequest () {
......
...@@ -13,7 +13,7 @@ define(['common/js/spec_helpers/ajax_helpers', 'js/shoppingcart/shoppingcart'], ...@@ -13,7 +13,7 @@ define(['common/js/spec_helpers/ajax_helpers', 'js/shoppingcart/shoppingcart'],
el: $('.confirm-enrollment.cart-view form') el: $('.confirm-enrollment.cart-view form')
}); });
spyOn(view, 'responseFromServer').andCallFake(function() {}); spyOn(view, 'responseFromServer').and.callFake(function() {});
// Spy on AJAX requests // Spy on AJAX requests
requests = AjaxHelpers.requests(this); requests = AjaxHelpers.requests(this);
...@@ -36,7 +36,7 @@ define(['common/js/spec_helpers/ajax_helpers', 'js/shoppingcart/shoppingcart'], ...@@ -36,7 +36,7 @@ define(['common/js/spec_helpers/ajax_helpers', 'js/shoppingcart/shoppingcart'],
}); });
expect(view.responseFromServer).toHaveBeenCalled(); expect(view.responseFromServer).toHaveBeenCalled();
var data = view.responseFromServer.mostRecentCall.args[0] var data = view.responseFromServer.calls.mostRecent().args[0];
expect(data.is_course_enrollment_closed).toBe(true); expect(data.is_course_enrollment_closed).toBe(true);
}); });
...@@ -50,7 +50,7 @@ define(['common/js/spec_helpers/ajax_helpers', 'js/shoppingcart/shoppingcart'], ...@@ -50,7 +50,7 @@ define(['common/js/spec_helpers/ajax_helpers', 'js/shoppingcart/shoppingcart'],
}); });
expect(view.responseFromServer).toHaveBeenCalled(); expect(view.responseFromServer).toHaveBeenCalled();
var data = view.responseFromServer.mostRecentCall.args[0] var data = view.responseFromServer.calls.mostRecent().args[0];
expect(data.is_course_enrollment_closed).toBe(false); expect(data.is_course_enrollment_closed).toBe(false);
}); });
......
...@@ -5,6 +5,8 @@ define([ ...@@ -5,6 +5,8 @@ define([
'common/js/spec_helpers/ajax_helpers' 'common/js/spec_helpers/ajax_helpers'
], ],
function (Backbone, $, tmp, AjaxHelpers) { function (Backbone, $, tmp, AjaxHelpers) {
'use strict';
var StaffDebug = window.StaffDebug;
describe('StaffDebugActions', function () { describe('StaffDebugActions', function () {
var location = 'i4x://edX/Open_DemoX/edx_demo_course/problem/test_loc'; var location = 'i4x://edX/Open_DemoX/edx_demo_course/problem/test_loc';
...@@ -20,8 +22,10 @@ define([ ...@@ -20,8 +22,10 @@ define([
describe('get_url ', function () { describe('get_url ', function () {
it('defines url to courseware ajax entry point', function () { it('defines url to courseware ajax entry point', function () {
spyOn(StaffDebug, "get_current_url").andReturn("/courses/edX/Open_DemoX/edx_demo_course/courseware/stuff"); spyOn(StaffDebug, "get_current_url")
expect(StaffDebug.get_url('rescore_problem')).toBe('/courses/edX/Open_DemoX/edx_demo_course/instructor/api/rescore_problem'); .and.returnValue("/courses/edX/Open_DemoX/edx_demo_course/courseware/stuff");
expect(StaffDebug.get_url('rescore_problem'))
.toBe('/courses/edX/Open_DemoX/edx_demo_course/instructor/api/rescore_problem');
}); });
}); });
...@@ -87,13 +91,13 @@ define([ ...@@ -87,13 +91,13 @@ define([
spyOn($, 'ajax'); spyOn($, 'ajax');
StaffDebug.reset(locationName, location); StaffDebug.reset(locationName, location);
expect($.ajax.mostRecentCall.args[0]['type']).toEqual('GET'); expect($.ajax.calls.mostRecent().args[0].type).toEqual('GET');
expect($.ajax.mostRecentCall.args[0]['data']).toEqual({ expect($.ajax.calls.mostRecent().args[0].data).toEqual({
'problem_to_reset': location, 'problem_to_reset': location,
'unique_student_identifier': 'userman', 'unique_student_identifier': 'userman',
'delete_module': false 'delete_module': false
}); });
expect($.ajax.mostRecentCall.args[0]['url']).toEqual( expect($.ajax.calls.mostRecent().args[0].url).toEqual(
'/instructor/api/reset_student_attempts' '/instructor/api/reset_student_attempts'
); );
$('#' + fixture_id).remove(); $('#' + fixture_id).remove();
...@@ -106,13 +110,13 @@ define([ ...@@ -106,13 +110,13 @@ define([
spyOn($, 'ajax'); spyOn($, 'ajax');
StaffDebug.sdelete(locationName, location); StaffDebug.sdelete(locationName, location);
expect($.ajax.mostRecentCall.args[0]['type']).toEqual('GET'); expect($.ajax.calls.mostRecent().args[0].type).toEqual('GET');
expect($.ajax.mostRecentCall.args[0]['data']).toEqual({ expect($.ajax.calls.mostRecent().args[0].data).toEqual({
'problem_to_reset': location, 'problem_to_reset': location,
'unique_student_identifier': 'userman', 'unique_student_identifier': 'userman',
'delete_module': true 'delete_module': true
}); });
expect($.ajax.mostRecentCall.args[0]['url']).toEqual( expect($.ajax.calls.mostRecent().args[0].url).toEqual(
'/instructor/api/reset_student_attempts' '/instructor/api/reset_student_attempts'
); );
...@@ -126,13 +130,13 @@ define([ ...@@ -126,13 +130,13 @@ define([
spyOn($, 'ajax'); spyOn($, 'ajax');
StaffDebug.rescore(locationName, location); StaffDebug.rescore(locationName, location);
expect($.ajax.mostRecentCall.args[0]['type']).toEqual('GET'); expect($.ajax.calls.mostRecent().args[0].type).toEqual('GET');
expect($.ajax.mostRecentCall.args[0]['data']).toEqual({ expect($.ajax.calls.mostRecent().args[0].data).toEqual({
'problem_to_reset': location, 'problem_to_reset': location,
'unique_student_identifier': 'userman', 'unique_student_identifier': 'userman',
'delete_module': false 'delete_module': false
}); });
expect($.ajax.mostRecentCall.args[0]['url']).toEqual( expect($.ajax.calls.mostRecent().args[0].url).toEqual(
'/instructor/api/rescore_problem' '/instructor/api/rescore_problem'
); );
$('#' + fixture_id).remove(); $('#' + fixture_id).remove();
......
...@@ -78,11 +78,11 @@ ...@@ -78,11 +78,11 @@
view = new AccessView(_.extend(options, {el: $logistrationElement})); view = new AccessView(_.extend(options, {el: $logistrationElement}));
// Mock the redirect call // Mock the redirect call
spyOn( view, 'redirect' ).andCallFake( function() {} ); spyOn( view, 'redirect' ).and.callFake( function() {} );
// Mock the enrollment and shopping cart interfaces // Mock the enrollment and shopping cart interfaces
spyOn( EnrollmentInterface, 'enroll' ).andCallFake( function() {} ); spyOn( EnrollmentInterface, 'enroll' ).and.callFake( function() {} );
spyOn( ShoppingCartInterface, 'addCourseToCart' ).andCallFake( function() {} ); spyOn( ShoppingCartInterface, 'addCourseToCart' ).and.callFake( function() {} );
}; };
var assertForms = function(visibleType, hiddenType) { var assertForms = function(visibleType, hiddenType) {
...@@ -101,6 +101,7 @@ ...@@ -101,6 +101,7 @@
}; };
beforeEach(function() { beforeEach(function() {
spyOn(window.history, 'pushState');
setFixtures('<div id="login-and-registration-container" class="login-register" />'); setFixtures('<div id="login-and-registration-container" class="login-register" />');
TemplateHelpers.installTemplate('templates/student_account/access'); TemplateHelpers.installTemplate('templates/student_account/access');
TemplateHelpers.installTemplate('templates/student_account/login'); TemplateHelpers.installTemplate('templates/student_account/login');
...@@ -139,9 +140,6 @@ ...@@ -139,9 +140,6 @@
it('toggles between the login and registration forms', function() { it('toggles between the login and registration forms', function() {
ajaxSpyAndInitialize(this, 'login'); ajaxSpyAndInitialize(this, 'login');
// Prevent URL from updating
spyOn(history, 'pushState').andCallFake( function() {} );
// Simulate selection of the registration form // Simulate selection of the registration form
selectForm('register'); selectForm('register');
assertForms('#register-form', '#login-form'); assertForms('#register-form', '#login-form');
......
...@@ -16,7 +16,11 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers ...@@ -16,7 +16,11 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers
beforeEach(function () { beforeEach(function () {
timerCallback = jasmine.createSpy('timerCallback'); timerCallback = jasmine.createSpy('timerCallback');
jasmine.Clock.useMock(); jasmine.clock().install();
});
afterEach(function() {
jasmine.clock().uninstall();
}); });
it("sends request to reset password on clicking link in PasswordFieldView", function() { it("sends request to reset password on clicking link in PasswordFieldView", function() {
......
...@@ -104,7 +104,7 @@ define(['js/student_account/account'], ...@@ -104,7 +104,7 @@ define(['js/student_account/account'],
var assertAjax = function(url, method, data) { var assertAjax = function(url, method, data) {
expect($.ajax).toHaveBeenCalled(); expect($.ajax).toHaveBeenCalled();
var ajaxArgs = $.ajax.mostRecentCall.args[0]; var ajaxArgs = $.ajax.calls.mostRecent().args[0];
expect(ajaxArgs.url).toEqual(url); expect(ajaxArgs.url).toEqual(url);
expect(ajaxArgs.type).toEqual(method); expect(ajaxArgs.type).toEqual(method);
expect(ajaxArgs.data).toEqual(data); expect(ajaxArgs.data).toEqual(data);
...@@ -127,7 +127,7 @@ define(['js/student_account/account'], ...@@ -127,7 +127,7 @@ define(['js/student_account/account'],
view = new edx.student.account.AccountView().render(); view = new edx.student.account.AccountView().render();
// Stub Ajax calls to return success/failure // Stub Ajax calls to return success/failure
spyOn($, "ajax").andCallFake(function() { spyOn($, "ajax").and.callFake(function() {
return $.Deferred(function(defer) { return $.Deferred(function(defer) {
if (ajaxSuccess) { if (ajaxSuccess) {
defer.resolve(); defer.resolve();
......
...@@ -11,7 +11,7 @@ define(['common/js/spec_helpers/ajax_helpers', 'js/student_account/enrollment'], ...@@ -11,7 +11,7 @@ define(['common/js/spec_helpers/ajax_helpers', 'js/student_account/enrollment'],
beforeEach(function() { beforeEach(function() {
// Mock the redirect call // Mock the redirect call
spyOn(EnrollmentInterface, 'redirect').andCallFake(function() {}); spyOn(EnrollmentInterface, 'redirect').and.callFake(function() {});
}); });
it('enrolls a user in a course', function() { it('enrolls a user in a course', function() {
......
...@@ -27,13 +27,13 @@ ...@@ -27,13 +27,13 @@
view = new FinishAuthView({}); view = new FinishAuthView({});
// Mock the redirect call // Mock the redirect call
spyOn( view, 'redirect' ).andCallFake( function() {} ); spyOn( view, 'redirect' ).and.callFake( function() {} );
// Mock the enrollment and shopping cart interfaces // Mock the enrollment and shopping cart interfaces
spyOn( EnrollmentInterface, 'enroll' ).andCallFake( function() {} ); spyOn( EnrollmentInterface, 'enroll' ).and.callFake( function() {} );
spyOn( ShoppingCartInterface, 'addCourseToCart' ).andCallFake( function() {} ); spyOn( ShoppingCartInterface, 'addCourseToCart' ).and.callFake( function() {} );
spyOn( EmailOptInInterface, 'setPreference' ) spyOn( EmailOptInInterface, 'setPreference' )
.andCallFake( function() { return {'always': function(r) { r(); }}; } ); .and.callFake( function() { return {'always': function(r) { r(); }}; } );
view.render(); view.render();
}; };
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
* should be prefixed with '?' * should be prefixed with '?'
*/ */
var setFakeQueryParams = function( params ) { var setFakeQueryParams = function( params ) {
spyOn( $, 'url' ).andCallFake(function( requestedParam ) { spyOn( $, 'url' ).and.callFake(function( requestedParam ) {
if ( params.hasOwnProperty(requestedParam) ) { if ( params.hasOwnProperty(requestedParam) ) {
return params[requestedParam]; return params[requestedParam];
} }
......
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
}); });
// Mock the redirect call // Mock the redirect call
spyOn( view, 'redirect' ).andCallFake( function() {} ); spyOn( view, 'redirect' ).and.callFake( function() {} );
view.render(); view.render();
}; };
......
...@@ -127,7 +127,7 @@ ...@@ -127,7 +127,7 @@
// spying on `view.validate` twice // spying on `view.validate` twice
if ( !_.isUndefined(validationSuccess) ) { if ( !_.isUndefined(validationSuccess) ) {
// Force validation to return as expected // Force validation to return as expected
spyOn(view, 'validate').andReturn({ spyOn(view, 'validate').and.returnValue({
isValid: validationSuccess, isValid: validationSuccess,
message: 'Submission was validated.' message: 'Submission was validated.'
}); });
...@@ -173,7 +173,7 @@ ...@@ -173,7 +173,7 @@
// Simulate that the user is attempting to enroll in a course // Simulate that the user is attempting to enroll in a course
// by setting the course_id query string param. // by setting the course_id query string param.
spyOn($, 'url').andCallFake(function( param ) { spyOn($, 'url').and.callFake(function( param ) {
if (param === '?course_id') { if (param === '?course_id') {
return encodeURIComponent( COURSE_ID ); return encodeURIComponent( COURSE_ID );
} }
......
...@@ -58,7 +58,7 @@ ...@@ -58,7 +58,7 @@
// spying on `view.validate` twice // spying on `view.validate` twice
if ( !_.isUndefined(validationSuccess) ) { if ( !_.isUndefined(validationSuccess) ) {
// Force validation to return as expected // Force validation to return as expected
spyOn(view, 'validate').andReturn({ spyOn(view, 'validate').and.returnValue({
isValid: validationSuccess, isValid: validationSuccess,
message: 'Submission was validated.' message: 'Submission was validated.'
}); });
......
...@@ -220,7 +220,7 @@ ...@@ -220,7 +220,7 @@
// spying on `view.validate` twice // spying on `view.validate` twice
if ( !_.isUndefined(validationSuccess) ) { if ( !_.isUndefined(validationSuccess) ) {
// Force validation to return as expected // Force validation to return as expected
spyOn(view, 'validate').andReturn({ spyOn(view, 'validate').and.returnValue({
isValid: validationSuccess, isValid: validationSuccess,
message: 'Submission was validated.' message: 'Submission was validated.'
}); });
...@@ -265,7 +265,7 @@ ...@@ -265,7 +265,7 @@
// Simulate that the user is attempting to enroll in a course // Simulate that the user is attempting to enroll in a course
// by setting the course_id query string param. // by setting the course_id query string param.
spyOn($, 'url').andCallFake(function( param ) { spyOn($, 'url').and.callFake(function( param ) {
if (param === '?course_id') { if (param === '?course_id') {
return encodeURIComponent( COURSE_ID ); return encodeURIComponent( COURSE_ID );
} }
......
...@@ -10,7 +10,7 @@ define(['common/js/spec_helpers/ajax_helpers', 'js/student_account/shoppingcart' ...@@ -10,7 +10,7 @@ define(['common/js/spec_helpers/ajax_helpers', 'js/student_account/shoppingcart'
beforeEach(function() { beforeEach(function() {
// Mock the redirect call // Mock the redirect call
spyOn(ShoppingCartInterface, 'redirect').andCallFake(function() {}); spyOn(ShoppingCartInterface, 'redirect').and.callFake(function() {});
}); });
it('adds a course to the cart', function() { it('adds a course to the cart', function() {
......
...@@ -22,51 +22,41 @@ define([ ...@@ -22,51 +22,41 @@ define([
}).render(); }).render();
}; };
var uploadImage = function( view, fileType, callback ) { var uploadImage = function( view, fileType ) {
var imageCapturedEvent = false, var deferred = $.Deferred();
errorEvent = false;
// Since image upload is an asynchronous process, // Since image upload is an asynchronous process,
// we need to wait for the upload to complete // we need to wait for the upload to complete
// before checking the outcome. // before checking the outcome.
runs(function() { var fakeFile,
var fakeFile, fakeEvent = { target: { files: [] } };
fakeEvent = { target: { files: [] } };
// If no file type is specified, don't add any files.
// If no file type is specified, don't add any files. // This simulates what happens when the user clicks
// This simulates what happens when the user clicks // "cancel" after clicking the input.
// "cancel" after clicking the input. if ( fileType !== null) {
if ( fileType !== null) { fakeFile = new Blob(
fakeFile = new Blob( [ IMAGE_DATA ],
[ IMAGE_DATA ], { type: 'image/' + fileType }
{ type: 'image/' + fileType } );
); fakeEvent.target.files = [ fakeFile ];
fakeEvent.target.files = [ fakeFile ]; }
}
// Wait for either a successful upload or an error
view.on( 'imageCaptured', function() {
imageCapturedEvent = true;
});
view.on( 'error', function() {
errorEvent = true;
});
// Trigger the file input change
// It's impossible to trigger this directly due
// to browser security restrictions, so we call
// the handler instead.
view.handleInputChange( fakeEvent );
});
// Check that the image upload has completed, // Wait for either a successful upload or an error
// either successfully or with an error. view.on( 'imageCaptured', function() {
waitsFor(function() { deferred.resolve();
return ( imageCapturedEvent || errorEvent ); });
view.on( 'error', function() {
deferred.resolve();
}); });
// Execute the callback to check expectations. // Trigger the file input change
runs( callback ); // It's impossible to trigger this directly due
// to browser security restrictions, so we call
// the handler instead.
view.handleInputChange( fakeEvent );
return deferred.promise();
}; };
var expectPreview = function( view, fileType ) { var expectPreview = function( view, fileType ) {
...@@ -112,45 +102,45 @@ define([ ...@@ -112,45 +102,45 @@ define([
expectSubmitEnabled( false ); expectSubmitEnabled( false );
}); });
it( 'uploads a png image', function() { it( 'uploads a png image', function(done) {
var view = createView(); var view = createView();
uploadImage( view, 'png', function() { uploadImage( view, 'png').then(function() {
expectPreview( view, 'png' ); expectPreview( view, 'png' );
expectSubmitEnabled( true ); expectSubmitEnabled( true );
expectImageData( view, 'png' ); expectImageData( view, 'png' );
}); }).always(done);
}); });
it( 'uploads a jpeg image', function() { it( 'uploads a jpeg image', function(done) {
var view = createView(); var view = createView();
uploadImage( view, 'jpeg', function() { uploadImage( view, 'jpeg').then(function() {
expectPreview( view, 'jpeg' ); expectPreview( view, 'jpeg' );
expectSubmitEnabled( true ); expectSubmitEnabled( true );
expectImageData( view, 'jpeg' ); expectImageData( view, 'jpeg' );
} ); }).always(done);
}); });
it( 'hides the preview when the user cancels the upload', function() { it( 'hides the preview when the user cancels the upload', function(done) {
var view = createView(); var view = createView();
uploadImage( view, null, function() { uploadImage( view, null).then(function() {
expectPreview( view, null ); expectPreview( view, null );
expectSubmitEnabled( false ); expectSubmitEnabled( false );
expectImageData( view, null ); expectImageData( view, null );
} ); }).always(done);
}); });
it( 'shows an error if the file type is not supported', function() { it( 'shows an error if the file type is not supported', function(done) {
var view = createView(); var view = createView();
uploadImage( view, 'txt', function() { uploadImage( view, 'txt').then(function() {
expectPreview( view, null ); expectPreview( view, null );
expectError( view ); expectError( view );
expectSubmitEnabled( false ); expectSubmitEnabled( false );
expectImageData( view, null ); expectImageData( view, null );
} ); }).always(done);
}); });
}); });
}); });
...@@ -37,7 +37,7 @@ define([ ...@@ -37,7 +37,7 @@ define([
}).render(); }).render();
// Stub the payment form submission // Stub the payment form submission
spyOn( view, 'submitForm' ).andCallFake( function() {} ); spyOn( view, 'submitForm' ).and.callFake( function() {} );
return view; return view;
}; };
...@@ -97,7 +97,7 @@ define([ ...@@ -97,7 +97,7 @@ define([
var form; var form;
expect(view.submitForm).toHaveBeenCalled(); expect(view.submitForm).toHaveBeenCalled();
form = view.submitForm.mostRecentCall.args[0]; form = view.submitForm.calls.mostRecent().args[0];
expect(form.serialize()).toEqual($.param(params)); expect(form.serialize()).toEqual($.param(params));
expect(form.attr('method')).toEqual('POST'); expect(form.attr('method')).toEqual('POST');
......
...@@ -34,7 +34,7 @@ define([ ...@@ -34,7 +34,7 @@ define([
}).render(); }).render();
// Stub the payment form submission // Stub the payment form submission
spyOn( view, 'submitForm' ).andCallFake( function() {} ); spyOn( view, 'submitForm' ).and.callFake( function() {} );
return view; return view;
}; };
...@@ -91,7 +91,7 @@ define([ ...@@ -91,7 +91,7 @@ define([
var form; var form;
expect(view.submitForm).toHaveBeenCalled(); expect(view.submitForm).toHaveBeenCalled();
form = view.submitForm.mostRecentCall.args[0]; form = view.submitForm.calls.mostRecent().args[0];
expect(form.serialize()).toEqual($.param(params)); expect(form.serialize()).toEqual($.param(params));
expect(form.attr('method')).toEqual("POST"); expect(form.attr('method')).toEqual("POST");
......
...@@ -68,6 +68,7 @@ define(['jquery', 'common/js/spec_helpers/template_helpers', 'js/verify_student/ ...@@ -68,6 +68,7 @@ define(['jquery', 'common/js/spec_helpers/template_helpers', 'js/verify_student/
beforeEach(function() { beforeEach(function() {
window.analytics = jasmine.createSpyObj('analytics', ['track', 'page', 'trackLink']); window.analytics = jasmine.createSpyObj('analytics', ['track', 'page', 'trackLink']);
navigator.getUserMedia = jasmine.createSpy();
setFixtures('<div id="pay-and-verify-container"></div>'); setFixtures('<div id="pay-and-verify-container"></div>');
$.each( TEMPLATES, function( index, templateName ) { $.each( TEMPLATES, function( index, templateName ) {
......
/** /**
* Tests for the reverification view. * Tests for the reverification view.
**/ **/
define(['jquery', 'common/js/spec_helpers/template_helpers', 'js/verify_student/views/reverify_view'], define(['jquery', 'common/js/spec_helpers/template_helpers', 'js/verify_student/views/review_photos_step_view',
function( $, TemplateHelpers, ReverifyView ) { 'js/verify_student/views/reverify_view'],
function( $, TemplateHelpers, ReviewPhotosStepView, ReverifyView ) {
'use strict'; 'use strict';
describe( 'edx.verify_student.ReverifyView', function() { describe( 'edx.verify_student.ReverifyView', function() {
...@@ -45,6 +46,7 @@ define(['jquery', 'common/js/spec_helpers/template_helpers', 'js/verify_student/ ...@@ -45,6 +46,7 @@ define(['jquery', 'common/js/spec_helpers/template_helpers', 'js/verify_student/
beforeEach(function() { beforeEach(function() {
window.analytics = jasmine.createSpyObj('analytics', ['track', 'page', 'trackLink']); window.analytics = jasmine.createSpyObj('analytics', ['track', 'page', 'trackLink']);
navigator.getUserMedia = jasmine.createSpy();
setFixtures('<div id="reverify-container"></div>'); setFixtures('<div id="reverify-container"></div>');
$.each( TEMPLATES, function( index, templateName ) { $.each( TEMPLATES, function( index, templateName ) {
......
...@@ -42,7 +42,7 @@ define([ ...@@ -42,7 +42,7 @@ define([
// Simulate the server response // Simulate the server response
if ( succeeds ) { if ( succeeds ) {
AjaxHelpers.respondWithJson( requests ); AjaxHelpers.respondWithJson( requests, {} );
} else { } else {
AjaxHelpers.respondWithTextError( requests, 400, SERVER_ERROR_MSG ); AjaxHelpers.respondWithTextError( requests, 400, SERVER_ERROR_MSG );
} }
......
...@@ -94,7 +94,7 @@ define([ ...@@ -94,7 +94,7 @@ define([
var view = createView( new StubBackend( "html5" ) ); var view = createView( new StubBackend( "html5" ) );
// Spy on the backend // Spy on the backend
spyOn( view.backend, 'snapshot' ).andCallThrough(); spyOn( view.backend, 'snapshot' ).and.callThrough();
// Initially, only the snapshot button is shown // Initially, only the snapshot button is shown
expectButtonShown({ expectButtonShown({
...@@ -125,7 +125,7 @@ define([ ...@@ -125,7 +125,7 @@ define([
var view = createView( new StubBackend( "html5" ) ); var view = createView( new StubBackend( "html5" ) );
// Spy on the backend // Spy on the backend
spyOn( view.backend, 'reset' ).andCallThrough(); spyOn( view.backend, 'reset' ).and.callThrough();
// Take the snapshot, then reset // Take the snapshot, then reset
takeSnapshot(); takeSnapshot();
......
...@@ -118,7 +118,7 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers ...@@ -118,7 +118,7 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers
expectMessageContains(view, view.helpMessage); expectMessageContains(view, view.helpMessage);
view.showSuccessMessage(); view.showSuccessMessage();
expectMessageContains(view, view.indicators.success); expectMessageContains(view, view.indicators.success);
jasmine.Clock.tick(7000); jasmine.clock().tick(7000);
// Message gets reset // Message gets reset
expectMessageContains(view, view.helpMessage); expectMessageContains(view, view.helpMessage);
...@@ -126,7 +126,7 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers ...@@ -126,7 +126,7 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers
expectMessageContains(view, view.indicators.success); expectMessageContains(view, view.indicators.success);
// But if we change the message, it should not get reset. // But if we change the message, it should not get reset.
view.showHelpMessage("Do not reset this!"); view.showHelpMessage("Do not reset this!");
jasmine.Clock.tick(7000); jasmine.clock().tick(7000);
expectMessageContains(view, "Do not reset this!"); expectMessageContains(view, "Do not reset this!");
}; };
......
...@@ -25,7 +25,11 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers ...@@ -25,7 +25,11 @@ define(['backbone', 'jquery', 'underscore', 'common/js/spec_helpers/ajax_helpers
beforeEach(function () { beforeEach(function () {
timerCallback = jasmine.createSpy('timerCallback'); timerCallback = jasmine.createSpy('timerCallback');
jasmine.Clock.useMock(); jasmine.clock().install();
});
afterEach(function() {
jasmine.clock().uninstall();
}); });
it("updates messages correctly for all fields", function() { it("updates messages correctly for all fields", function() {
......
...@@ -178,11 +178,15 @@ var edx = edx || {}; ...@@ -178,11 +178,15 @@ var edx = edx || {};
this.$passwordResetStatus this.$passwordResetStatus
.removeClass('error') .removeClass('error')
.text(""); .text("");
}, }
}); });
return new edx.student.account.AccountView({ try {
el: $('#account-container') new edx.student.account.AccountView({
}).render(); el: $('#account-container')
}).render();
} catch (e) {
// TODO: handle exception
}
})(jQuery, _, Backbone, gettext); })(jQuery, _, Backbone, gettext);
...@@ -31,7 +31,6 @@ lib_paths: ...@@ -31,7 +31,6 @@ lib_paths:
- xmodule_js/common_static/js/test/i18n.js - xmodule_js/common_static/js/test/i18n.js
- xmodule_js/common_static/coffee/src/ajax_prefix.js - xmodule_js/common_static/coffee/src/ajax_prefix.js
- xmodule_js/common_static/js/src/logger.js - xmodule_js/common_static/js/src/logger.js
- xmodule_js/common_static/js/vendor/jasmine-jquery.js
- xmodule_js/common_static/js/vendor/jasmine-imagediff.js - xmodule_js/common_static/js/vendor/jasmine-imagediff.js
- xmodule_js/common_static/js/vendor/requirejs/require.js - xmodule_js/common_static/js/vendor/requirejs/require.js
- js/RequireJS-namespace-undefine.js - js/RequireJS-namespace-undefine.js
......
...@@ -31,19 +31,21 @@ lib_paths: ...@@ -31,19 +31,21 @@ lib_paths:
- xmodule_js/common_static/js/test/i18n.js - xmodule_js/common_static/js/test/i18n.js
- xmodule_js/common_static/coffee/src/ajax_prefix.js - xmodule_js/common_static/coffee/src/ajax_prefix.js
- xmodule_js/common_static/js/src/logger.js - xmodule_js/common_static/js/src/logger.js
- xmodule_js/common_static/js/vendor/jasmine-jquery.js - xmodule_js/common_static/js/vendor/underscore-min.js
- xmodule_js/common_static/js/vendor/jasmine-imagediff.js - xmodule_js/common_static/js/vendor/jasmine-imagediff.js
- xmodule_js/common_static/js/vendor/requirejs/require.js - xmodule_js/common_static/js/vendor/requirejs/require.js
- js/RequireJS-namespace-undefine.js - js/RequireJS-namespace-undefine.js
- xmodule_js/common_static/js/vendor/jquery.min.js
- xmodule_js/common_static/js/vendor/jquery-ui.min.js - xmodule_js/common_static/js/vendor/jquery-ui.min.js
- xmodule_js/common_static/js/vendor/jquery.cookie.js - xmodule_js/common_static/js/vendor/jquery.cookie.js
- xmodule_js/common_static/js/vendor/flot/jquery.flot.js - xmodule_js/common_static/js/vendor/flot/jquery.flot.js
- xmodule_js/common_static/js/vendor/moment.min.js
- xmodule_js/common_static/js/vendor/moment-with-locales.min.js
- xmodule_js/common_static/js/vendor/CodeMirror/codemirror.js - xmodule_js/common_static/js/vendor/CodeMirror/codemirror.js
- xmodule_js/common_static/js/vendor/URI.min.js - xmodule_js/common_static/js/vendor/URI.min.js
- xmodule_js/common_static/coffee/src/jquery.immediateDescendents.js - xmodule_js/common_static/coffee/src/jquery.immediateDescendents.js
- xmodule_js/common_static/js/xblock - xmodule_js/common_static/js/xblock
- xmodule_js/common_static/coffee/src/xblock - xmodule_js/common_static/coffee/src/xblock
- moment_requirejs.js
- xmodule_js/src/capa/ - xmodule_js/src/capa/
- xmodule_js/src/video/ - xmodule_js/src/video/
- xmodule_js/src/xmodule.js - xmodule_js/src/xmodule.js
...@@ -75,7 +77,7 @@ fixture_paths: ...@@ -75,7 +77,7 @@ fixture_paths:
# When loading many files, this can be slow, so # When loading many files, this can be slow, so
# exclude any files you don't need. # exclude any files you don't need.
#exclude_from_page: #exclude_from_page:
# - path/to/lib/exclude/* # - coffee/spec/helper.js
# Regular expression used to guarantee that a *.js file # Regular expression used to guarantee that a *.js file
# is included in the test runner page. # is included in the test runner page.
......
...@@ -30,11 +30,10 @@ var files = [ ...@@ -30,11 +30,10 @@ var files = [
{pattern: 'xmodule_js/common_static/js/test/i18n.js', included: false}, {pattern: 'xmodule_js/common_static/js/test/i18n.js', included: false},
{pattern: 'xmodule_js/common_static/coffee/src/ajax_prefix.js', included: false}, {pattern: 'xmodule_js/common_static/coffee/src/ajax_prefix.js', included: false},
{pattern: 'xmodule_js/common_static/js/src/logger.js', included: false}, {pattern: 'xmodule_js/common_static/js/src/logger.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/jasmine-imagediff.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/requirejs/require.js', included: false}, {pattern: 'xmodule_js/common_static/js/vendor/requirejs/require.js', included: false},
{pattern: 'js/RequireJS-namespace-undefine.js', included: false}, {pattern: 'js/RequireJS-namespace-undefine.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/requirejs/text.js', included: false}, {pattern: 'xmodule_js/common_static/js/vendor/requirejs/text.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/jquery.min.js', included: false}, {pattern: 'xmodule_js/common_static/js/vendor/jquery.min.js', included: true},
{pattern: 'xmodule_js/common_static/js/vendor/jquery-ui.min.js', included: false}, {pattern: 'xmodule_js/common_static/js/vendor/jquery-ui.min.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/jquery.simulate.js', included: false}, {pattern: 'xmodule_js/common_static/js/vendor/jquery.simulate.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/jquery.cookie.js', included: false}, {pattern: 'xmodule_js/common_static/js/vendor/jquery.cookie.js', included: false},
...@@ -70,10 +69,9 @@ var files = [ ...@@ -70,10 +69,9 @@ var files = [
{pattern: 'xmodule_js/common_static/js/vendor/moment.min.js', included: false}, {pattern: 'xmodule_js/common_static/js/vendor/moment.min.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/moment-with-locales.min.js', included: false}, {pattern: 'xmodule_js/common_static/js/vendor/moment-with-locales.min.js', included: false},
{pattern: 'xmodule_js/common_static/common/js/utils/edx.utils.validate.js', included: false}, {pattern: 'xmodule_js/common_static/common/js/utils/edx.utils.validate.js', included: false},
{pattern: 'xmodule_js/common_static/js/vendor/slick.core.js', included: false}, {pattern: 'xmodule_js/common_static/js/vendor/jquery.event.drag-2.2.js', included: true},
{pattern: 'xmodule_js/common_static/js/vendor/slick.grid.js', included: false}, {pattern: 'xmodule_js/common_static/js/vendor/slick.core.js', included: true},
{pattern: 'xmodule_js/common_static/js/vendor/jquery.event.drag-2.2.js', included: false}, {pattern: 'xmodule_js/common_static/js/vendor/slick.grid.js', included: true},
{pattern: 'xmodule_js/common_static/js/libs/jasmine-waituntil.js', included: true},
// Paths to source JavaScript files // Paths to source JavaScript files
{pattern: 'js/**/*.js', included: false, nocache: true}, {pattern: 'js/**/*.js', included: false, nocache: true},
...@@ -85,6 +83,10 @@ var files = [ ...@@ -85,6 +83,10 @@ var files = [
{pattern: 'teams/js/**/*.js', included: false, nocache: true}, {pattern: 'teams/js/**/*.js', included: false, nocache: true},
{pattern: 'xmodule_js/common_static/coffee/**/*.js', included: false, nocache: true}, {pattern: 'xmodule_js/common_static/coffee/**/*.js', included: false, nocache: true},
// Paths to Jasmine plugins
{pattern: 'xmodule_js/common_static/js/libs/jasmine-waituntil.js', included: true},
{pattern: 'xmodule_js/common_static/js/libs/jasmine-extensions.js', included: true},
// Paths to spec (test) JavaScript files // Paths to spec (test) JavaScript files
{pattern: 'js/spec/**/*.js', included: false, nocache: true}, {pattern: 'js/spec/**/*.js', included: false, nocache: true},
{pattern: 'teams/js/spec/**/*.js', included: false, nocache: true}, {pattern: 'teams/js/spec/**/*.js', included: false, nocache: true},
......
...@@ -38,6 +38,7 @@ var files = [ ...@@ -38,6 +38,7 @@ var files = [
{pattern: 'xmodule_js/common_static/js/src/logger.js', included: true}, {pattern: 'xmodule_js/common_static/js/src/logger.js', included: true},
{pattern: 'xmodule_js/common_static/common/js/vendor/underscore.js', included: true}, {pattern: 'xmodule_js/common_static/common/js/vendor/underscore.js', included: true},
{pattern: 'xmodule_js/common_static/js/vendor/jasmine-imagediff.js', included: true}, {pattern: 'xmodule_js/common_static/js/vendor/jasmine-imagediff.js', included: true},
{pattern: 'xmodule_js/common_static/js/libs/jasmine-extensions.js', included: true},
{pattern: 'xmodule_js/common_static/js/vendor/requirejs/require.js', included: true}, {pattern: 'xmodule_js/common_static/js/vendor/requirejs/require.js', included: true},
{pattern: 'js/RequireJS-namespace-undefine.js', included: true}, {pattern: 'js/RequireJS-namespace-undefine.js', included: true},
{pattern: 'xmodule_js/common_static/js/vendor/jquery-ui.min.js', included: true}, {pattern: 'xmodule_js/common_static/js/vendor/jquery-ui.min.js', included: true},
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<object type="application/x-shockwave-flash" <object type="application/x-shockwave-flash"
id="flash_video" id="flash_video"
name="flash_video" name="flash_video"
data="/static/js/verify_student/CameraCapture.swf" data="js/verify_student/CameraCapture.swf"
width="500" width="500"
height="375"> height="375">
<param name="quality" value="high"> <param name="quality" value="high">
......
...@@ -120,20 +120,20 @@ class Env(object): ...@@ -120,20 +120,20 @@ class Env(object):
# TODO: Store this as a dict. Order seems to matter for some # TODO: Store this as a dict. Order seems to matter for some
# reason. See issue TE-415. # reason. See issue TE-415.
KARMA_CONFIG_FILES = [ KARMA_CONFIG_FILES = [
# REPO_ROOT / 'lms/static/karma_lms.conf.js',
# REPO_ROOT / 'lms/static/karma_lms_coffee.conf.js',
REPO_ROOT / 'cms/static/karma_cms.conf.js', REPO_ROOT / 'cms/static/karma_cms.conf.js',
REPO_ROOT / 'cms/static/karma_cms_squire.conf.js', REPO_ROOT / 'cms/static/karma_cms_squire.conf.js',
REPO_ROOT / 'lms/static/karma_lms.conf.js',
REPO_ROOT / 'lms/static/karma_lms_coffee.conf.js',
REPO_ROOT / 'common/lib/xmodule/xmodule/js/karma_xmodule.conf.js', REPO_ROOT / 'common/lib/xmodule/xmodule/js/karma_xmodule.conf.js',
REPO_ROOT / 'common/static/karma_common.conf.js', REPO_ROOT / 'common/static/karma_common.conf.js',
REPO_ROOT / 'common/static/karma_common_requirejs.conf.js', REPO_ROOT / 'common/static/karma_common_requirejs.conf.js',
] ]
JS_TEST_ID_KEYS = [ JS_TEST_ID_KEYS = [
# 'lms',
# 'lms-coffee',
'cms', 'cms',
'cms-squire', 'cms-squire',
'lms',
'lms-coffee',
'xmodule', 'xmodule',
'common', 'common',
'common-requirejs' 'common-requirejs'
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment