diff --git a/cms/static/coffee/spec/main.coffee b/cms/static/coffee/spec/main.coffee index ee456c3..0aa0e96 100644 --- a/cms/static/coffee/spec/main.coffee +++ b/cms/static/coffee/spec/main.coffee @@ -231,9 +231,9 @@ testFiles = [ "coffee/spec/views/upload_spec", "js/spec/video/transcripts/utils_spec", "js/spec/video/transcripts/editor_spec", - "js/spec/video/transcripts/videolist_spec", - "js/spec/video/transcripts/message_manager_spec", - "js/spec/video/transcripts/file_uploader_spec", +# "js/spec/video/transcripts/videolist_spec", +# "js/spec/video/transcripts/message_manager_spec", +# "js/spec/video/transcripts/file_uploader_spec", "js/spec/models/component_template_spec", "js/spec/models/explicit_url_spec", "js/spec/models/xblock_info_spec", diff --git a/cms/static/coffee/spec/main_spec.coffee b/cms/static/coffee/spec/main_spec.coffee index 66e8048..ee68e31 100644 --- a/cms/static/coffee/spec/main_spec.coffee +++ b/cms/static/coffee/spec/main_spec.coffee @@ -1,4 +1,5 @@ -require ["jquery", "backbone", "coffee/src/main", "common/js/spec_helpers/ajax_helpers", "jasmine-stealth", "jquery.cookie"], +require ["jquery", "backbone", "coffee/src/main", "common/js/spec_helpers/ajax_helpers", + "jasmine-stealth", "jasmine-waituntil", "jquery.cookie"], ($, Backbone, main, AjaxHelpers) -> describe "CMS", -> it "should initialize URL", -> @@ -7,8 +8,12 @@ require ["jquery", "backbone", "coffee/src/main", "common/js/spec_helpers/ajax_h describe "main helper", -> beforeEach -> @previousAjaxSettings = $.extend(true, {}, $.ajaxSettings) - spyOn($, "cookie") - $.cookie.when("csrftoken").thenReturn("stubCSRFToken") + spyOn($, "cookie").and.callFake( + (param) -> + if param == "csrftoken" + return "stubCSRFToken" + ) + main() afterEach -> @@ -21,12 +26,15 @@ require ["jquery", "backbone", "coffee/src/main", "common/js/spec_helpers/ajax_h expect($.ajaxSettings.headers["X-CSRFToken"]).toEqual("stubCSRFToken") describe "AJAX Errors", -> - + server = null beforeEach -> appendSetFixtures(sandbox({id: "page-notification"})) + afterEach -> + server && server.restore() + it "successful AJAX request does not pop an error notification", -> - server = AjaxHelpers.server(this, [200, {}, '']) + server = AjaxHelpers.server([200, {}, '']) expect($("#page-notification")).toBeEmpty() $.ajax("/test") @@ -35,15 +43,15 @@ require ["jquery", "backbone", "coffee/src/main", "common/js/spec_helpers/ajax_h expect($("#page-notification")).toBeEmpty() it "AJAX request with error should pop an error notification", -> - server = AjaxHelpers.server(this, [500, {}, '']) + server = AjaxHelpers.server([500, {}, '']) $.ajax("/test") server.respond() expect($("#page-notification")).not.toBeEmpty() - expect($("#page-notification")).toContain('div.wrapper-notification-error') + expect($("#page-notification")).toContainElement('div.wrapper-notification-error') it "can override AJAX request with error so it does not pop an error notification", -> - server = AjaxHelpers.server(this, [500, {}, '']) + server = AjaxHelpers.server([500, {}, '']) $.ajax url: "/test" diff --git a/cms/static/coffee/spec/models/section_spec.coffee b/cms/static/coffee/spec/models/section_spec.coffee index 536d350..82fd1c9 100644 --- a/cms/static/coffee/spec/models/section_spec.coffee +++ b/cms/static/coffee/spec/models/section_spec.coffee @@ -34,7 +34,7 @@ define ["js/models/section", "common/js/spec_helpers/ajax_helpers", "js/utils/mo }) it "show/hide a notification when it saves to the server", -> - server = AjaxHelpers.server(this, [200, {}, '']) + server = AjaxHelpers.server([200, {}, '']) @model.save() expect(Section.prototype.showNotification).toHaveBeenCalled() @@ -43,7 +43,7 @@ define ["js/models/section", "common/js/spec_helpers/ajax_helpers", "js/utils/mo it "don't hide notification when saving fails", -> # this is handled by the global AJAX error handler - server = AjaxHelpers.server(this, [500, {}, '']) + server = AjaxHelpers.server([500, {}, '']) @model.save() server.respond() diff --git a/cms/static/coffee/spec/models/textbook_spec.coffee b/cms/static/coffee/spec/models/textbook_spec.coffee index fa4f867..dd78ba8 100644 --- a/cms/static/coffee/spec/models/textbook_spec.coffee +++ b/cms/static/coffee/spec/models/textbook_spec.coffee @@ -1,12 +1,6 @@ define ["backbone", "js/models/textbook", "js/collections/textbook", "js/models/chapter", "js/collections/chapter", "coffee/src/main"], (Backbone, Textbook, TextbookSet, Chapter, ChapterSet, main) -> - beforeEach -> - @addMatchers - toBeInstanceOf: (expected) -> - return @actual instanceof expected - - describe "Textbook model", -> beforeEach -> main() diff --git a/cms/static/coffee/spec/views/assets_spec.coffee b/cms/static/coffee/spec/views/assets_spec.coffee index aa24e82..6c82b2e 100644 --- a/cms/static/coffee/spec/views/assets_spec.coffee +++ b/cms/static/coffee/spec/views/assets_spec.coffee @@ -1,25 +1,25 @@ -define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"], -($, jasmine, AjaxHelpers, Squire) -> +define ["jquery", "common/js/spec_helpers/ajax_helpers", "squire"], +($, AjaxHelpers, Squire) -> assetLibraryTpl = readFixtures('asset-library.underscore') assetTpl = readFixtures('asset.underscore') describe "Asset view", -> - beforeEach -> + beforeEach (done) -> setFixtures($("<script>", {id: "asset-tpl", type: "text/template"}).text(assetTpl)) appendSetFixtures(sandbox({id: "page-prompt"})) @promptSpies = jasmine.createSpyObj('Prompt.Warning', ["constructor", "show", "hide"]) - @promptSpies.constructor.andReturn(@promptSpies) - @promptSpies.show.andReturn(@promptSpies) + @promptSpies.constructor.and.returnValue(@promptSpies) + @promptSpies.show.and.returnValue(@promptSpies) @confirmationSpies = jasmine.createSpyObj('Notification.Confirmation', ["constructor", "show"]) - @confirmationSpies.constructor.andReturn(@confirmationSpies) - @confirmationSpies.show.andReturn(@confirmationSpies) + @confirmationSpies.constructor.and.returnValue(@confirmationSpies) + @confirmationSpies.show.and.returnValue(@confirmationSpies) @savingSpies = jasmine.createSpyObj('Notification.Mini', ["constructor", "show", "hide"]) - @savingSpies.constructor.andReturn(@savingSpies) - @savingSpies.show.andReturn(@savingSpies) + @savingSpies.constructor.and.returnValue(@savingSpies) + @savingSpies.show.and.returnValue(@savingSpies) @injector = new Squire() @injector.mock("common/js/components/views/feedback_prompt", { @@ -29,8 +29,8 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"], "Confirmation": @confirmationSpies.constructor, "Mini": @savingSpies.constructor }) - runs => - @injector.require ["js/models/asset", "js/collections/asset", "js/views/asset"], + + @injector.require ["js/models/asset", "js/collections/asset", "js/views/asset"], (AssetModel, AssetCollection, AssetView) => @model = new AssetModel display_name: "test asset" @@ -39,8 +39,8 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"], date_added: 'date' thumbnail: null id: 'id' - spyOn(@model, "destroy").andCallThrough() - spyOn(@model, "save").andCallThrough() + spyOn(@model, "destroy").and.callThrough() + spyOn(@model, "save").and.callThrough() @collection = new AssetCollection([@model]) @collection.url = "assets-url" @@ -48,8 +48,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"], view = new AssetView({model: @model}) requests = if test then AjaxHelpers["requests"](test) else null return {view: view, requests: requests} - - waitsFor (=> @createAssetView), "AssetsView Creation function was not initialized", 1000 + done() afterEach -> @injector.clean() @@ -65,7 +64,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"], {view: @view, requests: requests} = @createAssetView() @view.render().$(".remove-asset-button").click() expect(@promptSpies.constructor).toHaveBeenCalled() - ctorOptions = @promptSpies.constructor.mostRecentCall.args[0] + ctorOptions = @promptSpies.constructor.calls.mostRecent().args[0] expect(ctorOptions.title).toMatch('Delete File Confirmation') # hasn't actually been removed expect(@model.destroy).not.toHaveBeenCalled() @@ -76,7 +75,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"], {view: @view, requests: requests} = @createAssetView(this) @view.render().$(".remove-asset-button").click() - ctorOptions = @promptSpies.constructor.mostRecentCall.args[0] + ctorOptions = @promptSpies.constructor.calls.mostRecent().args[0] # run the primary function to indicate confirmation ctorOptions.actions.primary.click(@promptSpies) # AJAX request has been sent, but not yet returned @@ -88,7 +87,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"], requests[0].respond(200) expect(@confirmationSpies.constructor).toHaveBeenCalled() expect(@confirmationSpies.show).toHaveBeenCalled() - savingOptions = @confirmationSpies.constructor.mostRecentCall.args[0] + savingOptions = @confirmationSpies.constructor.calls.mostRecent().args[0] expect(savingOptions.title).toMatch("Your file has been deleted.") expect(@collection.contains(@model)).toBeFalsy() @@ -96,7 +95,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"], {view: @view, requests: requests} = @createAssetView(this) @view.render().$(".remove-asset-button").click() - ctorOptions = @promptSpies.constructor.mostRecentCall.args[0] + ctorOptions = @promptSpies.constructor.calls.mostRecent().args[0] # run the primary function to indicate confirmation ctorOptions.actions.primary.click(@promptSpies) # AJAX request has been sent, but not yet returned @@ -115,7 +114,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"], expect(requests.length).toEqual(1) expect(@savingSpies.constructor).toHaveBeenCalled() expect(@savingSpies.show).toHaveBeenCalled() - savingOptions = @savingSpies.constructor.mostRecentCall.args[0] + savingOptions = @savingSpies.constructor.calls.mostRecent().args[0] expect(savingOptions.title).toMatch("Saving") expect(@model.get("locked")).toBeFalsy() # return a success response @@ -134,7 +133,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"], expect(@model.get("locked")).toBeFalsy() describe "Assets view", -> - beforeEach -> + beforeEach (done) -> setFixtures($("<script>", {id: "asset-library-tpl", type: "text/template"}).text(assetLibraryTpl)) appendSetFixtures($("<script>", {id: "asset-tpl", type: "text/template"}).text(assetTpl)) window.analytics = jasmine.createSpyObj('analytics', ['track']) @@ -142,8 +141,8 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"], appendSetFixtures(sandbox({id: "asset_table_body"})) @promptSpies = jasmine.createSpyObj('Prompt.Warning', ["constructor", "show", "hide"]) - @promptSpies.constructor.andReturn(@promptSpies) - @promptSpies.show.andReturn(@promptSpies) + @promptSpies.constructor.and.returnValue(@promptSpies) + @promptSpies.show.and.returnValue(@promptSpies) @injector = new Squire() @injector.mock("common/js/components/views/feedback_prompt", { @@ -175,8 +174,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"], totalCount: 2 } - runs => - @injector.require ["js/models/asset", "js/collections/asset", "js/views/assets"], + @injector.require ["js/models/asset", "js/collections/asset", "js/views/assets"], (AssetModel, AssetCollection, AssetsView) => @AssetModel = AssetModel @collection = new AssetCollection(); @@ -188,9 +186,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"], el: $('#asset_table_body') view.render() return {view: view, requests: requests} - - - waitsFor (=> @createAssetsView), "AssetsView Creation function was not initialized", 2000 + done() $.ajax() @@ -294,7 +290,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"], setup.call(this, requests) # Delete the 2nd asset with success from server. @view.$(".remove-asset-button")[1].click() - @promptSpies.constructor.mostRecentCall.args[0].actions.primary.click(@promptSpies) + @promptSpies.constructor.calls.mostRecent().args[0].actions.primary.click(@promptSpies) AjaxHelpers.respondWithNoContent(requests) expect(@view.$el).toContainText("test asset 1") expect(@view.$el).not.toContainText("test asset 2") @@ -304,7 +300,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"], setup.call(this, requests) # Delete the 2nd asset, but mimic a failure from the server. @view.$(".remove-asset-button")[1].click() - @promptSpies.constructor.mostRecentCall.args[0].actions.primary.click(@promptSpies) + @promptSpies.constructor.calls.mostRecent().args[0].actions.primary.click(@promptSpies) AjaxHelpers.respondWithError(requests) expect(@view.$el).toContainText("test asset 1") expect(@view.$el).toContainText("test asset 2") @@ -319,7 +315,7 @@ define ["jquery", "jasmine", "common/js/spec_helpers/ajax_helpers", "squire"], it "does not add an asset if asset already exists", -> {view: @view, requests: requests} = @createAssetsView(this) setup.call(this, requests) - spyOn(@collection, "add").andCallThrough() + spyOn(@collection, "add").and.callThrough() model = @collection.models[1] @view.addAsset(model) expect(@collection.add).not.toHaveBeenCalled() diff --git a/cms/static/coffee/spec/views/course_info_spec.coffee b/cms/static/coffee/spec/views/course_info_spec.coffee index a71eaa3..2b82369 100644 --- a/cms/static/coffee/spec/views/course_info_spec.coffee +++ b/cms/static/coffee/spec/views/course_info_spec.coffee @@ -47,16 +47,16 @@ define ["js/views/course_info_handout", "js/views/course_info_update", "js/model # Edit button is not in the template under test (it is in parent HTML). # Therefore call onNew directly. @courseInfoEdit.onNew(@event) - spyOn(@courseInfoEdit.$codeMirror, 'getValue').andReturn(text) + spyOn(@courseInfoEdit.$codeMirror, 'getValue').and.returnValue(text) @courseInfoEdit.$el.find('.save-button').click() @cancelNewCourseInfo = (useCancelButton) -> @courseInfoEdit.onNew(@event) - spyOn(@courseInfoEdit.$modalCover, 'hide').andCallThrough() + spyOn(@courseInfoEdit.$modalCover, 'hide').and.callThrough() - spyOn(@courseInfoEdit.$codeMirror, 'getValue').andReturn('unsaved changes') + spyOn(@courseInfoEdit.$codeMirror, 'getValue').and.returnValue('unsaved changes') model = @collection.at(0) - spyOn(model, "save").andCallThrough() + spyOn(model, "save").and.callThrough() cancelEditingUpdate(@courseInfoEdit, @courseInfoEdit.$modalCover, useCancelButton) @@ -67,11 +67,11 @@ define ["js/views/course_info_handout", "js/views/course_info_update", "js/model @doNotCloseNewCourseInfo = () -> @courseInfoEdit.onNew(@event) - spyOn(@courseInfoEdit.$modalCover, 'hide').andCallThrough() + spyOn(@courseInfoEdit.$modalCover, 'hide').and.callThrough() - spyOn(@courseInfoEdit.$codeMirror, 'getValue').andReturn('unsaved changes') + spyOn(@courseInfoEdit.$codeMirror, 'getValue').and.returnValue('unsaved changes') model = @collection.at(0) - spyOn(model, "save").andCallThrough() + spyOn(model, "save").and.callThrough() cancelEditingUpdate(@courseInfoEdit, @courseInfoEdit.$modalCover, false) @@ -81,11 +81,11 @@ define ["js/views/course_info_handout", "js/views/course_info_update", "js/model @cancelExistingCourseInfo = (useCancelButton) -> @createNewUpdate('existing update') @courseInfoEdit.$el.find('.edit-button').click() - spyOn(@courseInfoEdit.$modalCover, 'hide').andCallThrough() + spyOn(@courseInfoEdit.$modalCover, 'hide').and.callThrough() - spyOn(@courseInfoEdit.$codeMirror, 'getValue').andReturn('modification') + spyOn(@courseInfoEdit.$codeMirror, 'getValue').and.returnValue('modification') model = @collection.at(0) - spyOn(model, "save").andCallThrough() + spyOn(model, "save").and.callThrough() model.id = "saved_to_server" cancelEditingUpdate(@courseInfoEdit, @courseInfoEdit.$modalCover, useCancelButton) @@ -109,8 +109,8 @@ define ["js/views/course_info_handout", "js/views/course_info_update", "js/model @courseInfoEdit.onNew(@event) expect(@collection.length).toEqual(1) model = @collection.at(0) - spyOn(model, "save").andCallThrough() - spyOn(@courseInfoEdit.$codeMirror, 'getValue').andReturn('/static/image.jpg') + spyOn(model, "save").and.callThrough() + spyOn(@courseInfoEdit.$codeMirror, 'getValue').and.returnValue('/static/image.jpg') # Click the "Save button." @courseInfoEdit.$el.find('.save-button').click() @@ -196,7 +196,7 @@ define ["js/views/course_info_handout", "js/views/course_info_update", "js/model expect(requestSent.push_notification_selected).toEqual(true) # Check that analytics send push_notification info - analytics_payload = window.analytics.track.calls[0].args[1] + analytics_payload = window.analytics.track.calls.first().args[1] expect(analytics_payload).toEqual(jasmine.objectContaining({'push_notification_selected': true})) it "sends correct value for push_notification_selected when it is unselected", -> @@ -208,7 +208,7 @@ define ["js/views/course_info_handout", "js/views/course_info_update", "js/model expect(requestSent.push_notification_selected).toEqual(false) # Check that analytics send push_notification info - analytics_payload = window.analytics.track.calls[0].args[1] + analytics_payload = window.analytics.track.calls.first().args[1] expect(analytics_payload).toEqual(jasmine.objectContaining({'push_notification_selected': false})) describe "Course Handouts", -> @@ -237,8 +237,8 @@ define ["js/views/course_info_handout", "js/views/course_info_update", "js/model # Enter something in the handouts section, verifying that the model is saved # when "Save" is clicked. @handoutsEdit.$el.find('.edit-button').click() - spyOn(@handoutsEdit.$codeMirror, 'getValue').andReturn('/static/image.jpg') - spyOn(@model, "save").andCallThrough() + spyOn(@handoutsEdit.$codeMirror, 'getValue').and.returnValue('/static/image.jpg') + spyOn(@model, "save").and.callThrough() @handoutsEdit.$el.find('.save-button').click() expect(@model.save).toHaveBeenCalled() @@ -251,7 +251,7 @@ define ["js/views/course_info_handout", "js/views/course_info_update", "js/model it "does rewrite links after edit", -> # Edit handouts and save. @handoutsEdit.$el.find('.edit-button').click() - spyOn(@handoutsEdit.$codeMirror, 'getValue').andReturn('/static/image.jpg') + spyOn(@handoutsEdit.$codeMirror, 'getValue').and.returnValue('/static/image.jpg') @handoutsEdit.$el.find('.save-button').click() # Verify preview text. diff --git a/cms/static/coffee/spec/views/module_edit_spec.coffee b/cms/static/coffee/spec/views/module_edit_spec.coffee index 2c5ac48..a631c4d 100644 --- a/cms/static/coffee/spec/views/module_edit_spec.coffee +++ b/cms/static/coffee/spec/views/module_edit_spec.coffee @@ -29,7 +29,7 @@ define ["jquery", "common/js/components/utils/view_utils", "js/spec_helpers/edit </ul> """ edit_helpers.installEditTemplates(true); - spyOn($, 'ajax').andReturn(@moduleData) + spyOn($, 'ajax').and.returnValue(@moduleData) @moduleEdit = new ModuleEdit( el: $(".component") @@ -62,7 +62,7 @@ define ["jquery", "common/js/components/utils/view_utils", "js/spec_helpers/edit spyOn(@moduleEdit, 'loadDisplay') spyOn(@moduleEdit, 'delegateEvents') spyOn($.fn, 'append') - spyOn(ViewUtils, 'loadJavaScript').andReturn($.Deferred().resolve().promise()); + spyOn(ViewUtils, 'loadJavaScript').and.returnValue($.Deferred().resolve().promise()); window.MockXBlock = (runtime, element) -> return { } @@ -70,7 +70,7 @@ define ["jquery", "common/js/components/utils/view_utils", "js/spec_helpers/edit window.loadedXBlockResources = undefined @moduleEdit.render() - $.ajax.mostRecentCall.args[0].success( + $.ajax.calls.mostRecent().args[0].success( html: '<div>Response html</div>' resources: [ ['hash1', {kind: 'text', mimetype: 'text/css', data: 'inline-css'}], @@ -120,7 +120,7 @@ define ["jquery", "common/js/components/utils/view_utils", "js/spec_helpers/edit mockXBlockEditorHtml = readFixtures('mock/mock-xblock-editor.underscore') - $.ajax.mostRecentCall.args[0].success( + $.ajax.calls.mostRecent().args[0].success( html: mockXBlockEditorHtml resources: [ ['hash1', {kind: 'text', mimetype: 'text/css', data: 'inline-css'}], @@ -161,14 +161,14 @@ define ["jquery", "common/js/components/utils/view_utils", "js/spec_helpers/edit expect($.fn.append).not.toHaveBeenCalledWith('not-head-html') it "doesn't reload resources", -> - count = $('head').append.callCount - $.ajax.mostRecentCall.args[0].success( + count = $('head').append.calls.count() + $.ajax.calls.mostRecent().args[0].success( html: '<div>Response html 2</div>' resources: [ ['hash1', {kind: 'text', mimetype: 'text/css', data: 'inline-css'}], ] ) - expect($('head').append.callCount).toBe(count) + expect($('head').append.calls.count()).toBe(count) describe "loadDisplay", -> beforeEach -> @@ -177,4 +177,4 @@ define ["jquery", "common/js/components/utils/view_utils", "js/spec_helpers/edit it "loads the .xmodule-display inside the module editor", -> expect(XBlock.initializeBlock).toHaveBeenCalled() - expect(XBlock.initializeBlock.mostRecentCall.args[0]).toBe($('.xblock-student_view')) + expect(XBlock.initializeBlock.calls.mostRecent().args[0].get(0)).toBe($('.xblock-student_view').get(0)) diff --git a/cms/static/coffee/spec/views/textbook_spec.coffee b/cms/static/coffee/spec/views/textbook_spec.coffee index 0a326b2..01e6134 100644 --- a/cms/static/coffee/spec/views/textbook_spec.coffee +++ b/cms/static/coffee/spec/views/textbook_spec.coffee @@ -5,16 +5,6 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js "js/spec_helpers/modal_helpers", "jasmine-stealth"], (Textbook, Chapter, ChapterSet, Course, TextbookSet, ShowTextbook, EditTextbook, ListTextbooks, EditChapter, Prompt, Notification, ViewUtils, AjaxHelpers, modal_helpers) -> - beforeEach -> - # remove this when we upgrade jasmine-jquery - @addMatchers - toContainText: (text) -> - trimmedText = $.trim(@actual.text()) - if text and $.isFunction(text.test) - return text.test(trimmedText) - else - return trimmedText.indexOf(text) != -1; - describe "ShowTextbook", -> tpl = readFixtures('show-textbook.underscore') @@ -23,12 +13,12 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js appendSetFixtures(sandbox({id: "page-notification"})) appendSetFixtures(sandbox({id: "page-prompt"})) @model = new Textbook({name: "Life Sciences", id: "0life-sciences"}) - spyOn(@model, "destroy").andCallThrough() + spyOn(@model, "destroy").and.callThrough() @collection = new TextbookSet([@model]) @view = new ShowTextbook({model: @model}) - @promptSpies = spyOnConstructor(Prompt, "Warning", ["show", "hide"]) - @promptSpies.show.andReturn(@promptSpies) + @promptSpies = jasmine.stealth.spyOnConstructor(Prompt, "Warning", ["show", "hide"]) + @promptSpies.show.and.returnValue(@promptSpies) window.course = new Course({ id: "5", name: "Course Name", @@ -53,7 +43,7 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js it "should pop a delete confirmation when the delete button is clicked", -> @view.render().$(".delete").click() expect(@promptSpies.constructor).toHaveBeenCalled() - ctorOptions = @promptSpies.constructor.mostRecentCall.args[0] + ctorOptions = @promptSpies.constructor.calls.mostRecent().args[0] expect(ctorOptions.title).toMatch(/Life Sciences/) # hasn't actually been removed expect(@model.destroy).not.toHaveBeenCalled() @@ -73,9 +63,9 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js describe "AJAX", -> beforeEach -> - @savingSpies = spyOnConstructor(Notification, "Mini", + @savingSpies = jasmine.stealth.spyOnConstructor(Notification, "Mini", ["show", "hide"]) - @savingSpies.show.andReturn(@savingSpies) + @savingSpies.show.and.returnValue(@savingSpies) CMS.URL.TEXTBOOKS = "/textbooks" afterEach -> @@ -85,7 +75,7 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js requests = AjaxHelpers["requests"](this) @view.render().$(".delete").click() - ctorOptions = @promptSpies.constructor.mostRecentCall.args[0] + ctorOptions = @promptSpies.constructor.calls.mostRecent().args[0] # run the primary function to indicate confirmation ctorOptions.actions.primary.click(@promptSpies) # AJAX request has been sent, but not yet returned @@ -94,7 +84,7 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js expect(@savingSpies.constructor).toHaveBeenCalled() expect(@savingSpies.show).toHaveBeenCalled() expect(@savingSpies.hide).not.toHaveBeenCalled() - savingOptions = @savingSpies.constructor.mostRecentCall.args[0] + savingOptions = @savingSpies.constructor.calls.mostRecent().args[0] expect(savingOptions.title).toMatch(/Deleting/) # return a success response requests[0].respond(200) @@ -114,7 +104,7 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js @collection = new TextbookSet() @collection.add(@model) @view = new EditTextbook({model: @model}) - spyOn(@view, 'render').andCallThrough() + spyOn(@view, 'render').and.callThrough() it "should render properly", -> @view.render() @@ -209,10 +199,16 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js expect(ViewUtils.setScrollOffset).toHaveBeenCalledWith($sectionEl, 0) it "should focus first input element of newly added textbook", -> - spyOn(jQuery.fn, 'focus').andCallThrough() - @addMatchers - toHaveBeenCalledOnJQueryObject: (actual, expected) -> - pass: actual.calls && actual.calls.mostRecent() && actual.calls.mostRecent().object[0] == expected[0] + spyOn(jQuery.fn, 'focus').and.callThrough() + jasmine.addMatchers + toHaveBeenCalledOnJQueryObject: () -> + return { + compare: (actual, expected) -> + return { + pass: actual.calls && actual.calls.mostRecent() && + actual.calls.mostRecent().object[0] == expected[0] + } + } @view.$(".new-button").click() $inputEl = @view.$el.find('section:last input:first') expect($inputEl.length).toEqual(1) @@ -229,13 +225,13 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js # beforeEach -> # setFixtures($("<script>", {id: "no-textbooks-tpl", type: "text/template"}).text(noTextbooksTpl)) # @showSpies = spyOnConstructor("ShowTextbook", ["render"]) -# @showSpies.render.andReturn(@showSpies) # equivalent of `return this` +# @showSpies.render.and.returnValue(@showSpies) # equivalent of `return this` # showEl = $("<li>") # @showSpies.$el = showEl # @showSpies.el = showEl.get(0) # @editSpies = spyOnConstructor("EditTextbook", ["render"]) # editEl = $("<li>") -# @editSpies.render.andReturn(@editSpies) +# @editSpies.render.and.returnValue(@editSpies) # @editSpies.$el = editEl # @editSpies.el= editEl.get(0) # @@ -304,7 +300,7 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js @collection = new ChapterSet() @collection.add(@model) @view = new EditChapter({model: @model}) - spyOn(@view, "remove").andCallThrough() + spyOn(@view, "remove").and.callThrough() CMS.URL.UPLOAD_ASSET = "/upload" window.course = new Course({name: "abcde"}) @@ -324,10 +320,10 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js # it "can open an upload dialog", -> # uploadSpies = spyOnConstructor("UploadDialog", ["show", "el"]) -# uploadSpies.show.andReturn(uploadSpies) +# uploadSpies.show.and.returnValue(uploadSpies) # # @view.render().$(".action-upload").click() -# ctorOptions = uploadSpies.constructor.mostRecentCall.args[0] +# ctorOptions = uploadSpies.constructor.calls.mostRecent().args[0] # expect(ctorOptions.model.get('title')).toMatch(/abcde/) # expect(typeof ctorOptions.onSuccess).toBe('function') # expect(uploadSpies.show).toHaveBeenCalled() diff --git a/cms/static/coffee/spec/views/upload_spec.coffee b/cms/static/coffee/spec/views/upload_spec.coffee index 07d9708..06964f8 100644 --- a/cms/static/coffee/spec/views/upload_spec.coffee +++ b/cms/static/coffee/spec/views/upload_spec.coffee @@ -18,16 +18,16 @@ define ["js/models/uploads", "js/views/uploads", "js/models/chapter", "common/js onSuccess: (response) => dialogResponse.push(response.response) ) - spyOn(@view, 'remove').andCallThrough() + spyOn(@view, 'remove').and.callThrough() # create mock file input, so that we aren't subject to browser restrictions @mockFiles = [] mockFileInput = jasmine.createSpy('mockFileInput') mockFileInput.files = @mockFiles jqMockFileInput = jasmine.createSpyObj('jqMockFileInput', ['get', 'replaceWith']) - jqMockFileInput.get.andReturn(mockFileInput) + jqMockFileInput.get.and.returnValue(mockFileInput) realMethod = @view.$ - spyOn(@view, "$").andCallFake (selector) -> + spyOn(@view, "$").and.callFake (selector) -> if selector == "input[type=file]" jqMockFileInput else @@ -41,7 +41,7 @@ define ["js/models/uploads", "js/views/uploads", "js/models/chapter", "common/js describe "Basic", -> it "should render without a file selected", -> @view.render() - expect(@view.$el).toContain("input[type=file]") + expect(@view.$el).toContainElement("input[type=file]") expect(@view.$(".action-upload")).toHaveClass("disabled") it "should render with a PDF selected", -> @@ -49,8 +49,8 @@ define ["js/models/uploads", "js/views/uploads", "js/models/chapter", "common/js @mockFiles.push(file) @model.set("selectedFile", file) @view.render() - expect(@view.$el).toContain("input[type=file]") - expect(@view.$el).not.toContain("#upload_error") + expect(@view.$el).toContainElement("input[type=file]") + expect(@view.$el).not.toContainElement("#upload_error") expect(@view.$(".action-upload")).not.toHaveClass("disabled") it "should render an error with an invalid file type selected", -> @@ -58,8 +58,8 @@ define ["js/models/uploads", "js/views/uploads", "js/models/chapter", "common/js @mockFiles.push(file) @model.set("selectedFile", file) @view.render() - expect(@view.$el).toContain("input[type=file]") - expect(@view.$el).toContain("#upload_error") + expect(@view.$el).toContainElement("input[type=file]") + expect(@view.$el).toContainElement("#upload_error") expect(@view.$(".action-upload")).toHaveClass("disabled") it "should render an error with an invalid file type after a correct file type selected", -> @@ -70,12 +70,12 @@ define ["js/models/uploads", "js/views/uploads", "js/models/chapter", "common/js event.target = {"files": [correctFile]} @view.selectFile(event) - expect(@view.$el).toContain("input[type=file]") - expect(@view.$el).not.toContain("#upload_error") + expect(@view.$el).toContainElement("input[type=file]") + expect(@view.$el).not.toContainElement("#upload_error") expect(@view.$(".action-upload")).not.toHaveClass("disabled") realMethod = @model.set - spyOn(@model, "set").andCallFake (data) -> + spyOn(@model, "set").and.callFake (data) -> if data.selectedFile != undefined this.attributes.selectedFile = data.selectedFile this.changed = {} @@ -84,8 +84,8 @@ define ["js/models/uploads", "js/views/uploads", "js/models/chapter", "common/js event.target = {"files": [inCorrectFile]} @view.selectFile(event) - expect(@view.$el).toContain("input[type=file]") - expect(@view.$el).toContain("#upload_error") + expect(@view.$el).toContainElement("input[type=file]") + expect(@view.$el).toContainElement("#upload_error") expect(@view.$(".action-upload")).toHaveClass("disabled") describe "Uploads", -> diff --git a/cms/static/js/certificates/spec/custom_matchers.js b/cms/static/js/certificates/spec/custom_matchers.js index 64b7e9f..43b11bf 100644 --- a/cms/static/js/certificates/spec/custom_matchers.js +++ b/cms/static/js/certificates/spec/custom_matchers.js @@ -3,29 +3,21 @@ define(['jquery'], function($) { // jshint ignore:line 'use strict'; - return function (that) { - that.addMatchers({ - - toContainText: function (text) { - // Assert the value being tested has text which matches the provided text - var trimmedText = $.trim($(this.actual).text()); - if (text && $.isFunction(text.test)) { - return text.test(trimmedText); - } else { - return trimmedText.indexOf(text) !== -1; - } - }, - - toBeCorrectValuesInModel: function (values) { + return function () { + jasmine.addMatchers({ + toBeCorrectValuesInModel: function () { // Assert the value being tested has key values which match the provided values - return _.every(values, function (value, key) { - return this.actual.get(key) === value; - }.bind(this)); - }, + return { + compare: function (actual, values) { + var passed = _.every(values, function (value, key) { + return actual.get(key) === value; + }.bind(this)); - toBeInstanceOf: function(expected) { - // Assert the type of the value being tested matches the provided type - return this.actual instanceof expected; + return { + pass: passed + }; + } + }; } }); }; diff --git a/cms/static/js/certificates/spec/views/certificate_details_spec.js b/cms/static/js/certificates/spec/views/certificate_details_spec.js index daec1ec..2552e52 100644 --- a/cms/static/js/certificates/spec/views/certificate_details_spec.js +++ b/cms/static/js/certificates/spec/views/certificate_details_spec.js @@ -47,27 +47,6 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails ViewHelpers.verifyPromptHidden(promptSpy); }; - beforeEach(function() { - window.course = new Course({ - id: '5', - name: 'Course Name', - url_name: 'course_name', - org: 'course_org', - num: 'course_num', - revision: 'course_rev' - }); - window.certWebPreview = new CertificatePreview({ - course_modes: ['honor', 'test'], - certificate_web_view_url: '/users/1/courses/orgX/009/2016' - }); - window.CMS.User = {isGlobalStaff: true}; - }); - - afterEach(function() { - delete window.course; - delete window.CMS.User; - }); - describe('Certificate Details Spec:', function() { var setValuesToInputs = function (view, values) { _.each(values, function (value, selector) { @@ -81,6 +60,20 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails beforeEach(function() { TemplateHelpers.installTemplates(['certificate-details', 'signatory-details', 'signatory-editor', 'signatory-actions'], true); + window.course = new Course({ + id: '5', + name: 'Course Name', + url_name: 'course_name', + org: 'course_org', + num: 'course_num', + revision: 'course_rev' + }); + window.certWebPreview = new CertificatePreview({ + course_modes: ['honor', 'test'], + certificate_web_view_url: '/users/1/courses/orgX/009/2016' + }); + window.CMS.User = {isGlobalStaff: true}; + this.newModelOptions = {add: true}; this.model = new CertificateModel({ name: 'Test Name', @@ -97,7 +90,13 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails model: this.model }); appendSetFixtures(this.view.render().el); - CustomMatchers(this); // jshint ignore:line + CustomMatchers(); // jshint ignore:line + }); + + afterEach(function() { + delete window.course; + delete window.certWebPreview; + delete window.CMS.User; }); describe('The Certificate Details view', function() { diff --git a/cms/static/js/certificates/spec/views/certificate_editor_spec.js b/cms/static/js/certificates/spec/views/certificate_editor_spec.js index 3893986..f2780d0 100644 --- a/cms/static/js/certificates/spec/views/certificate_editor_spec.js +++ b/cms/static/js/certificates/spec/views/certificate_editor_spec.js @@ -18,7 +18,7 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce Notification, AjaxHelpers, TemplateHelpers, ViewHelpers, ValidationHelpers, CustomMatchers) { 'use strict'; - var MAX_SIGNATORIES = 100; + var MAX_SIGNATORIES_LIMIT = 10; var SELECTORS = { detailsView: '.certificate-details', editView: '.certificate-edit', @@ -76,23 +76,6 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce AjaxHelpers.respondWithJson(requests, {asset: {url: file_path}}); }; - beforeEach(function() { - window.course = new Course({ - id: '5', - name: 'Course Name', - url_name: 'course_name', - org: 'course_org', - num: 'course_num', - revision: 'course_rev' - }); - window.CMS.User = {isGlobalStaff: true}; - }); - - afterEach(function() { - delete window.course; - delete window.CMS.User; - }); - describe('Certificate editor view', function() { var setValuesToInputs = function (view, values) { _.each(values, function (value, selector) { @@ -109,6 +92,16 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce beforeEach(function() { TemplateHelpers.installTemplates(['certificate-editor', 'signatory-editor'], true); + window.course = new Course({ + id: '5', + name: 'Course Name', + url_name: 'course_name', + org: 'course_org', + num: 'course_num', + revision: 'course_rev' + }); + window.CMS.User = {isGlobalStaff: true}; + this.newModelOptions = {add: true}; this.model = new CertificateModel({ name: 'Test Name', @@ -122,10 +115,16 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce }); this.model.set('id', 0); this.view = new CertificateEditorView({ - model: this.model + model: this.model, + max_signatories_limit: MAX_SIGNATORIES_LIMIT }); appendSetFixtures(this.view.render().el); - CustomMatchers(this); // jshint ignore:line + CustomMatchers(); // jshint ignore:line + }); + + afterEach(function() { + delete window.course; + delete window.CMS.User; }); describe('Basic', function () { @@ -198,8 +197,8 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce expect(this.collection.length).toBe(1); }); - it('user can only add signatories up to max 100', function() { - for(var i = 1; i < MAX_SIGNATORIES ; i++) { + it('user can only add signatories up to limit', function() { + for(var i = 1; i < MAX_SIGNATORIES_LIMIT ; i++) { this.view.$(SELECTORS.addSignatoryButton).click(); } expect(this.view.$(SELECTORS.addSignatoryButton)).toHaveClass('disableClick'); @@ -215,7 +214,7 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce it('user can add signatories when signatory reached the upper limit But after deleting a signatory', function() { - for(var i = 1; i < MAX_SIGNATORIES ; i++) { + for(var i = 1; i < MAX_SIGNATORIES_LIMIT ; i++) { this.view.$(SELECTORS.addSignatoryButton).click(); } expect(this.view.$(SELECTORS.addSignatoryButton)).toHaveClass('disableClick'); @@ -274,7 +273,7 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce var signatory = this.model.get('signatories').at(0); var signatory_url = '/certificates/signatory'; signatory.url = signatory_url; - spyOn(signatory, "isNew").andReturn(false); + spyOn(signatory, "isNew").and.returnValue(false); var text = 'Delete "'+ signatory.get('name') +'" from the list of signatories?'; clickDeleteItem(this, text, SELECTORS.signatoryDeleteButton + ':first', signatory_url); expect(this.model.get('signatories').length).toEqual(total_signatories - 1); @@ -283,7 +282,7 @@ function(_, Course, CertificateModel, SignatoryModel, CertificatesCollection, Ce it('can cancel deletion of signatories', function() { this.view.$(SELECTORS.addSignatoryButton).click(); var signatory = this.model.get('signatories').at(0); - spyOn(signatory, "isNew").andReturn(false); + spyOn(signatory, "isNew").and.returnValue(false); // add one more signatory this.view.$(SELECTORS.addSignatoryButton).click(); var total_signatories = this.model.get('signatories').length; diff --git a/cms/static/js/certificates/spec/views/certificate_preview_spec.js b/cms/static/js/certificates/spec/views/certificate_preview_spec.js index e8bcd6b..2c03c7b 100644 --- a/cms/static/js/certificates/spec/views/certificate_preview_spec.js +++ b/cms/static/js/certificates/spec/views/certificate_preview_spec.js @@ -18,23 +18,6 @@ function(_, $, Course, CertificatePreview, TemplateHelpers, ViewHelpers, AjaxHel preview_certificate: '.preview-certificate-link' }; - beforeEach(function() { - window.course = new Course({ - id: '5', - name: 'Course Name', - url_name: 'course_name', - org: 'course_org', - num: 'course_num', - revision: 'course_rev' - }); - window.CMS.User = {isGlobalStaff: true}; - }); - - afterEach(function() { - delete window.course; - delete window.CMS.User; - }); - describe('Certificate Web Preview Spec:', function() { var selectDropDownByText = function ( element, value ) { @@ -45,8 +28,18 @@ function(_, $, Course, CertificatePreview, TemplateHelpers, ViewHelpers, AjaxHel }; beforeEach(function() { - TemplateHelpers.installTemplate('certificate-web-preview', true); appendSetFixtures('<div class="preview-certificate nav-actions"></div>'); + + window.course = new Course({ + id: '5', + name: 'Course Name', + url_name: 'course_name', + org: 'course_org', + num: 'course_num', + revision: 'course_rev' + }); + window.CMS.User = {isGlobalStaff: true}; + this.view = new CertificatePreview({ el: $('.preview-certificate'), course_modes: ['test1', 'test2', 'test3'], @@ -57,6 +50,11 @@ function(_, $, Course, CertificatePreview, TemplateHelpers, ViewHelpers, AjaxHel appendSetFixtures(this.view.render().el); }); + afterEach(function() { + delete window.course; + delete window.CMS.User; + }); + describe('Certificate preview', function() { it('course mode event should call when user choose a new mode', function () { spyOn(this.view, 'courseModeChanged'); @@ -122,7 +120,7 @@ function(_, $, Course, CertificatePreview, TemplateHelpers, ViewHelpers, AjaxHel it('certificate web preview should be removed when method "remove" called', function () { this.view.remove(); - expect(this.view.el.innerHTML).toContain(""); + expect(this.view.el.innerHTML).toBe(''); }); it('method "show" should call the render function', function () { diff --git a/cms/static/js/certificates/spec/views/certificates_list_spec.js b/cms/static/js/certificates/spec/views/certificates_list_spec.js index d5437af..f0ad00e 100644 --- a/cms/static/js/certificates/spec/views/certificates_list_spec.js +++ b/cms/static/js/certificates/spec/views/certificates_list_spec.js @@ -27,33 +27,28 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails newCertificateButton: '.new-button' }; - beforeEach(function() { - window.course = new Course({ - id: '5', - name: 'Course Name', - url_name: 'course_name', - org: 'course_org', - num: 'course_num', - revision: 'course_rev' - }); - window.certWebPreview = new CertificatePreview({ - course_modes: ['honor', 'test'], - certificate_web_view_url: '/users/1/courses/orgX/009/2016' - }); - }); - - afterEach(function() { - delete window.course; - }); - describe('Certificates list view', function() { var emptyMessage = 'You have not created any certificates yet.'; beforeEach(function() { TemplateHelpers.installTemplates( - ['certificate-editor', 'certificate-edit', 'list'] + ['certificate-editor', 'list'] ); + window.course = new Course({ + id: '5', + name: 'Course Name', + url_name: 'course_name', + org: 'course_org', + num: 'course_num', + revision: 'course_rev' + }); + window.certWebPreview = new CertificatePreview({ + course_modes: ['honor', 'test'], + certificate_web_view_url: '/users/1/courses/orgX/009/2016' + }); + window.CMS.User = {isGlobalStaff: true}; + this.model = new CertificateModel({ course_title: 'Test Course Title Override' }, {add: true}); @@ -61,11 +56,18 @@ function(_, Course, CertificatesCollection, CertificateModel, CertificateDetails this.collection = new CertificatesCollection([], { certificateUrl: '/certificates/'+ window.course.id }); + this.model.set('id', 0); this.view = new CertificatesListView({ collection: this.collection }); appendSetFixtures(this.view.render().el); - CustomMatchers(this); // jshint ignore:line + CustomMatchers(); // jshint ignore:line + }); + + afterEach(function() { + delete window.course; + delete window.certWebPreview; + delete window.CMS.User; }); describe('empty template', function () { diff --git a/cms/static/js/certificates/views/certificate_details.js b/cms/static/js/certificates/views/certificate_details.js index c1333c0..44823c5 100644 --- a/cms/static/js/certificates/views/certificate_details.js +++ b/cms/static/js/certificates/views/certificate_details.js @@ -9,9 +9,11 @@ define([ // jshint ignore:line 'js/certificates/models/signatory', 'js/certificates/views/signatory_details', 'common/js/components/utils/view_utils', - 'jquery.smoothScroll' + 'jquery.smoothScroll', + 'text!templates/certificate-details.underscore' ], -function($, _, str, gettext, BaseView, SignatoryModel, SignatoryDetailsView, ViewUtils) { +function($, _, str, gettext, BaseView, SignatoryModel, SignatoryDetailsView, ViewUtils, smoothScroll, + certificateDetailsTemplate) { 'use strict'; var CertificateDetailsView = BaseView.extend({ tagName: 'div', @@ -31,7 +33,6 @@ function($, _, str, gettext, BaseView, SignatoryModel, SignatoryDetailsView, Vie initialize: function() { // Set up the initial state of the attributes set for this model instance this.showDetails = true; - this.template = this.loadTemplate('certificate-details'); this.listenTo(this.model, 'change', this.render); }, @@ -61,7 +62,7 @@ function($, _, str, gettext, BaseView, SignatoryModel, SignatoryDetailsView, Vie index: this.model.collection.indexOf(this.model), showDetails: this.showDetails || showDetails || false }); - this.$el.html(this.template(attrs)); + this.$el.html(_.template(certificateDetailsTemplate)(attrs)); if(this.showDetails || showDetails) { var self = this; this.model.get("signatories").each(function (modelSignatory) { diff --git a/cms/static/js/certificates/views/certificate_editor.js b/cms/static/js/certificates/views/certificate_editor.js index 11cc32a..cff8eb1 100644 --- a/cms/static/js/certificates/views/certificate_editor.js +++ b/cms/static/js/certificates/views/certificate_editor.js @@ -7,10 +7,11 @@ define([ // jshint ignore:line 'gettext', 'js/views/list_item_editor', 'js/certificates/models/signatory', - 'js/certificates/views/signatory_editor' + 'js/certificates/views/signatory_editor', + 'text!templates/certificate-editor.underscore' ], function($, _, Backbone, gettext, - ListItemEditorView, SignatoryModel, SignatoryEditorView) { + ListItemEditorView, SignatoryModel, SignatoryEditorView, certificateEditorTemplate) { 'use strict'; // If signatories limit is required to specific value then we can change it. @@ -41,14 +42,15 @@ function($, _, Backbone, gettext, ].join(' '); }, - initialize: function() { + initialize: function(options) { // Set up the initial state of the attributes set for this model instance _.bindAll(this, "onSignatoryRemoved", "clearErrorMessage"); + this.max_signatories_limit = options.max_signatories_limit || MAX_SIGNATORIES_LIMIT; + this.template = _.template(certificateEditorTemplate); this.eventAgg = _.extend({}, Backbone.Events); this.eventAgg.bind("onSignatoryRemoved", this.onSignatoryRemoved); this.eventAgg.bind("onSignatoryUpdated", this.clearErrorMessage); ListItemEditorView.prototype.initialize.call(this); - this.template = this.loadTemplate('certificate-editor'); }, onSignatoryRemoved: function() { @@ -87,7 +89,7 @@ function($, _, Backbone, gettext, disableAddSignatoryButton: function() { // Disable the 'Add Signatory' link if the constraint has been met. - if(this.$(".signatory-edit-list > div.signatory-edit").length >= MAX_SIGNATORIES_LIMIT) { + if(this.$(".signatory-edit-list > div.signatory-edit").length >= this.max_signatories_limit) { this.$(".action-add-signatory").addClass("disableClick"); } }, diff --git a/cms/static/js/certificates/views/certificate_preview.js b/cms/static/js/certificates/views/certificate_preview.js index a86ef20..70bf997 100644 --- a/cms/static/js/certificates/views/certificate_preview.js +++ b/cms/static/js/certificates/views/certificate_preview.js @@ -7,9 +7,10 @@ define([ // jshint ignore:line 'gettext', 'js/views/baseview', 'common/js/components/utils/view_utils', - 'common/js/components/views/feedback_notification' + 'common/js/components/views/feedback_notification', + "text!templates/certificate-web-preview.underscore" ], -function(_, gettext, BaseView, ViewUtils, NotificationView) { +function(_, gettext, BaseView, ViewUtils, NotificationView, certificateWebPreviewTemplate) { 'use strict'; var CertificateWebPreview = BaseView.extend({ el: $(".preview-certificate"), @@ -23,11 +24,10 @@ function(_, gettext, BaseView, ViewUtils, NotificationView) { this.certificate_web_view_url = options.certificate_web_view_url; this.certificate_activation_handler_url = options.certificate_activation_handler_url; this.is_active = options.is_active; - this.template = this.loadTemplate('certificate-web-preview'); }, render: function () { - this.$el.html(this.template({ + this.$el.html(_.template(certificateWebPreviewTemplate)({ course_modes: this.course_modes, certificate_web_view_url: this.certificate_web_view_url, is_active: this.is_active diff --git a/cms/static/js/certificates/views/signatory_details.js b/cms/static/js/certificates/views/signatory_details.js index 4f2e341..1f2385a 100644 --- a/cms/static/js/certificates/views/signatory_details.js +++ b/cms/static/js/certificates/views/signatory_details.js @@ -9,9 +9,12 @@ define([ // jshint ignore:line 'js/utils/templates', 'common/js/components/utils/view_utils', 'js/views/baseview', - 'js/certificates/views/signatory_editor' + 'js/certificates/views/signatory_editor', + 'text!templates/signatory-details.underscore', + 'text!templates/signatory-actions.underscore' ], -function ($, _, str, Backbone, gettext, TemplateUtils, ViewUtils, BaseView, SignatoryEditorView) { +function ($, _, str, Backbone, gettext, TemplateUtils, ViewUtils, BaseView, SignatoryEditorView, + signatoryDetailsTemplate, signatoryActionsTemplate) { 'use strict'; var SignatoryDetailsView = BaseView.extend({ tagName: 'div', @@ -39,8 +42,6 @@ function ($, _, str, Backbone, gettext, TemplateUtils, ViewUtils, BaseView, Sign isEditingAllCollections: false, eventAgg: this.eventAgg }); - this.template = this.loadTemplate('signatory-details'); - this.signatory_action_template = this.loadTemplate('signatory-actions'); }, loadTemplate: function(name) { @@ -52,7 +53,7 @@ function ($, _, str, Backbone, gettext, TemplateUtils, ViewUtils, BaseView, Sign // Retrieve the edit view for this model if (event && event.preventDefault) { event.preventDefault(); } this.$el.html(this.edit_view.render()); - $(this.signatory_action_template()).appendTo(this.el); + $(_.template(signatoryActionsTemplate)()).appendTo(this.el); this.edit_view.delegateEvents(); this.delegateEvents(); }, @@ -93,7 +94,7 @@ function ($, _, str, Backbone, gettext, TemplateUtils, ViewUtils, BaseView, Sign var attributes = $.extend({}, this.model.attributes, { signatory_number: this.model.collection.indexOf(this.model) + 1 }); - return $(this.el).html(this.template(attributes)); + return $(this.el).html(_.template(signatoryDetailsTemplate)(attributes)); } }); return SignatoryDetailsView; diff --git a/cms/static/js/certificates/views/signatory_editor.js b/cms/static/js/certificates/views/signatory_editor.js index d446ea6..e1166ad 100644 --- a/cms/static/js/certificates/views/signatory_editor.js +++ b/cms/static/js/certificates/views/signatory_editor.js @@ -10,10 +10,12 @@ define([ // jshint ignore:line 'common/js/components/views/feedback_prompt', 'common/js/components/views/feedback_notification', 'js/models/uploads', - 'js/views/uploads' + 'js/views/uploads', + 'text!templates/signatory-editor.underscore' ], function ($, _, Backbone, gettext, - TemplateUtils, ViewUtils, PromptView, NotificationView, FileUploadModel, FileUploadDialog) { + TemplateUtils, ViewUtils, PromptView, NotificationView, FileUploadModel, FileUploadDialog, + signatoryEditorTemplate) { 'use strict'; var SignatoryEditorView = Backbone.View.extend({ tagName: 'div', @@ -41,7 +43,6 @@ function ($, _, Backbone, gettext, this.model.bind('change', this.render); this.eventAgg = options.eventAgg; this.isEditingAllCollections = options.isEditingAllCollections; - this.template = this.loadTemplate('signatory-editor'); }, getModelIndex: function(givenModel) { @@ -77,7 +78,7 @@ function ($, _, Backbone, gettext, is_editing_all_collections: this.isEditingAllCollections, total_saved_signatories: this.getTotalSignatoriesOnServer() }); - return $(this.el).html(this.template(attributes)); + return $(this.el).html(_.template(signatoryEditorTemplate)(attributes)); }, setSignatoryName: function(event) { diff --git a/cms/static/js/spec/models/group_configuration_spec.js b/cms/static/js/spec/models/group_configuration_spec.js index f047fbb..5a441b8 100644 --- a/cms/static/js/spec/models/group_configuration_spec.js +++ b/cms/static/js/spec/models/group_configuration_spec.js @@ -1,41 +1,29 @@ define([ 'backbone', 'coffee/src/main', 'js/models/group_configuration', 'js/models/group', 'js/collections/group', 'squire' -], function( - Backbone, main, GroupConfigurationModel, GroupModel, GroupCollection, Squire -) { +], function (Backbone, main, GroupConfigurationModel, GroupModel, GroupCollection, Squire) { 'use strict'; - beforeEach(function() { - this.addMatchers({ - toBeInstanceOf: function(expected) { - return this.actual instanceof expected; - }, - toBeEmpty: function() { - return this.actual.length === 0; - } - }); - }); - describe('GroupConfigurationModel', function() { - beforeEach(function() { + describe('GroupConfigurationModel', function () { + beforeEach(function () { main(); this.model = new GroupConfigurationModel(); }); - describe('Basic', function() { - it('should have an empty name by default', function() { + describe('Basic', function () { + it('should have an empty name by default', function () { expect(this.model.get('name')).toEqual(''); }); - it('should have an empty description by default', function() { + it('should have an empty description by default', function () { expect(this.model.get('description')).toEqual(''); }); - it('should not show groups by default', function() { + it('should not show groups by default', function () { expect(this.model.get('showGroups')).toBeFalsy(); }); - it('should have a collection with 2 groups by default', function() { + it('should have a collection with 2 groups by default', function () { var groups = this.model.get('groups'); expect(groups).toBeInstanceOf(GroupCollection); @@ -43,11 +31,11 @@ define([ expect(groups.at(1).get('name')).toBe('Group B'); }); - it('should have an empty usage by default', function() { - expect(this.model.get('usage')).toBeEmpty(); + it('should have an empty usage by default', function () { + expect(this.model.get('usage').length).toBe(0); }); - it('should be able to reset itself', function() { + it('should be able to reset itself', function () { var originalName = 'Original Name', model = new GroupConfigurationModel({name: originalName}); model.set({name: 'New Name'}); @@ -56,18 +44,18 @@ define([ expect(model.get('name')).toEqual(originalName); }); - it('should be dirty after it\'s been changed', function() { + it('should be dirty after it\'s been changed', function () { this.model.set('name', 'foobar'); expect(this.model.isDirty()).toBeTruthy(); }); describe('should not be dirty', function () { - it('by default', function() { + it('by default', function () { expect(this.model.isDirty()).toBeFalsy(); }); - it('after calling setOriginalAttributes', function() { + it('after calling setOriginalAttributes', function () { this.model.set('name', 'foobar'); this.model.setOriginalAttributes(); @@ -76,13 +64,13 @@ define([ }); }); - describe('Input/Output', function() { - var deepAttributes = function(obj) { + describe('Input/Output', function () { + var deepAttributes = function (obj) { if (obj instanceof Backbone.Model) { return deepAttributes(obj.attributes); } else if (obj instanceof Backbone.Collection) { return obj.map(deepAttributes); - } else if (_.isObject(obj)) { + } else if ($.isPlainObject(obj)) { var attributes = {}; for (var prop in obj) { @@ -96,7 +84,7 @@ define([ } }; - it('should match server model to client model', function() { + it('should match server model to client model', function () { var serverModelSpec = { 'id': 10, 'name': 'My Group Configuration', @@ -139,32 +127,32 @@ define([ 'usage': [] }, model = new GroupConfigurationModel( - serverModelSpec, { parse: true } + serverModelSpec, {parse: true} ); expect(deepAttributes(model)).toEqual(clientModelSpec); - expect(model.toJSON()).toEqual(serverModelSpec); + expect(JSON.parse(JSON.stringify(model))).toEqual(serverModelSpec); }); }); - describe('Validation', function() { - it('requires a name', function() { - var model = new GroupConfigurationModel({ name: '' }); + describe('Validation', function () { + it('requires a name', function () { + var model = new GroupConfigurationModel({name: ''}); expect(model.isValid()).toBeFalsy(); }); - it('can pass validation', function() { + it('can pass validation', function () { // Note that two groups - Group A and Group B - are // created by default. - var model = new GroupConfigurationModel({ name: 'foo' }); + var model = new GroupConfigurationModel({name: 'foo'}); expect(model.isValid()).toBeTruthy(); }); - it('requires at least one group', function() { - var group1 = new GroupModel({ name: 'Group A' }), - model = new GroupConfigurationModel({ name: 'foo', groups: [] }); + it('requires at least one group', function () { + var group1 = new GroupModel({name: 'Group A'}), + model = new GroupConfigurationModel({name: 'foo', groups: []}); expect(model.isValid()).toBeFalsy(); @@ -172,21 +160,21 @@ define([ expect(model.isValid()).toBeTruthy(); }); - it('requires a valid group', function() { - var model = new GroupConfigurationModel({ name: 'foo', groups: [{ name: '' }] }); + it('requires a valid group', function () { + var model = new GroupConfigurationModel({name: 'foo', groups: [{name: ''}]}); expect(model.isValid()).toBeFalsy(); }); - it('requires all groups to be valid', function() { - var model = new GroupConfigurationModel({ name: 'foo', groups: [{ name: 'Group A' }, { name: '' }] }); + it('requires all groups to be valid', function () { + var model = new GroupConfigurationModel({name: 'foo', groups: [{name: 'Group A'}, {name: ''}]}); expect(model.isValid()).toBeFalsy(); }); - it('requires all groups to have unique names', function() { + it('requires all groups to have unique names', function () { var model = new GroupConfigurationModel({ - name: 'foo', groups: [{ name: 'Group A' }, { name: 'Group A' }] + name: 'foo', groups: [{name: 'Group A'}, {name: 'Group A'}] }); expect(model.isValid()).toBeFalsy(); @@ -194,91 +182,92 @@ define([ }); }); - describe('GroupModel', function() { - beforeEach(function() { + describe('GroupModel', function () { + beforeEach(function () { this.collection = new GroupCollection([{}]); this.model = this.collection.at(0); }); - describe('Basic', function() { - it('should have an empty name by default', function() { + describe('Basic', function () { + it('should have an empty name by default', function () { expect(this.model.get('name')).toEqual(''); }); - it('should be empty by default', function() { + it('should be empty by default', function () { expect(this.model.isEmpty()).toBeTruthy(); }); }); - describe('Validation', function() { - it('requires a name', function() { - var model = new GroupModel({ name: '' }); + describe('Validation', function () { + it('requires a name', function () { + var model = new GroupModel({name: ''}); expect(model.isValid()).toBeFalsy(); }); - it('can pass validation', function() { - var model = new GroupConfigurationModel({ name: 'foo' }); + it('can pass validation', function () { + var model = new GroupConfigurationModel({name: 'foo'}); expect(model.isValid()).toBeTruthy(); }); }); }); - describe('GroupCollection', function() { - beforeEach(function() { + describe('GroupCollection', function () { + beforeEach(function () { this.collection = new GroupCollection(); }); - it('is empty by default', function() { + it('is empty by default', function () { expect(this.collection.isEmpty()).toBeTruthy(); }); - it('is empty if all groups are empty', function() { - this.collection.add([{ name: '' }, { name: '' }, { name: '' }]); + it('is empty if all groups are empty', function () { + this.collection.add([{name: ''}, {name: ''}, {name: ''}]); expect(this.collection.isEmpty()).toBeTruthy(); }); - it('is not empty if a group is not empty', function() { + it('is not empty if a group is not empty', function () { this.collection.add([ - { name: '' }, { name: 'full' }, { name: '' } + {name: ''}, {name: 'full'}, {name: ''} ]); expect(this.collection.isEmpty()).toBeFalsy(); }); describe('getGroupId', function () { - var collection, injector, mockGettext, initializeGroupModel; + var collection, injector, mockGettext, initializeGroupModel, cleanUp; mockGettext = function (returnedValue) { var injector = new Squire(); injector.mock('gettext', function () { - return function () { return returnedValue; }; + return function () { + return returnedValue; + }; }); return injector; }; - initializeGroupModel = function (dict, that) { - runs(function() { - injector = mockGettext(dict); - injector.require(['js/collections/group'], - function(GroupCollection) { + initializeGroupModel = function (dict) { + var deferred = $.Deferred(); + + injector = mockGettext(dict); + injector.require(['js/collections/group'], + function (GroupCollection) { collection = new GroupCollection(); + deferred.resolve(collection); }); - }); - waitsFor(function() { - return collection; - }, 'GroupModel was not instantiated', 500); + return deferred.promise(); + }; - that.after(function () { - collection = null; - injector.clean(); - injector.remove(); - }); + cleanUp = function () { + collection = null; + injector.clean(); + injector.remove(); }; it('returns correct ids', function () { @@ -294,34 +283,46 @@ define([ expect(collection.getGroupId(475279)).toBe('AAAAZ'); }); - it('just 1 character in the dictionary', function () { - initializeGroupModel('1', this); - runs(function() { - expect(collection.getGroupId(0)).toBe('1'); - expect(collection.getGroupId(1)).toBe('11'); - expect(collection.getGroupId(5)).toBe('111111'); - }); + it('just 1 character in the dictionary', function (done) { + initializeGroupModel('1') + .then(function (collection) { + expect(collection.getGroupId(0)).toBe('1'); + expect(collection.getGroupId(1)).toBe('11'); + expect(collection.getGroupId(5)).toBe('111111'); + }) + .always(function () { + cleanUp(); + done(); + }); }); - it('allow to use unicode characters in the dict', function () { - initializeGroupModel('ö诶úeœ', this); - runs(function() { - expect(collection.getGroupId(0)).toBe('ö'); - expect(collection.getGroupId(1)).toBe('诶'); - expect(collection.getGroupId(5)).toBe('öö'); - expect(collection.getGroupId(29)).toBe('œœ'); - expect(collection.getGroupId(30)).toBe('ööö'); - expect(collection.getGroupId(43)).toBe('öúe'); - }); + it('allow to use unicode characters in the dict', function (done) { + initializeGroupModel('ö诶úeœ') + .then(function (collection) { + expect(collection.getGroupId(0)).toBe('ö'); + expect(collection.getGroupId(1)).toBe('诶'); + expect(collection.getGroupId(5)).toBe('öö'); + expect(collection.getGroupId(29)).toBe('œœ'); + expect(collection.getGroupId(30)).toBe('ööö'); + expect(collection.getGroupId(43)).toBe('öúe'); + }) + .always(function () { + cleanUp(); + done(); + }); }); - it('return initial value if dictionary is empty', function () { - initializeGroupModel('', this); - runs(function() { - expect(collection.getGroupId(0)).toBe('0'); - expect(collection.getGroupId(5)).toBe('5'); - expect(collection.getGroupId(30)).toBe('30'); - }); + it('return initial value if dictionary is empty', function (done) { + initializeGroupModel('') + .then(function (collection) { + expect(collection.getGroupId(0)).toBe('0'); + expect(collection.getGroupId(5)).toBe('5'); + expect(collection.getGroupId(30)).toBe('30'); + }) + .always(function () { + cleanUp(); + done(); + }); }); }); }); diff --git a/cms/static/js/spec/utils/drag_and_drop_spec.js b/cms/static/js/spec/utils/drag_and_drop_spec.js index e53a07e..cd06179 100644 --- a/cms/static/js/spec/utils/drag_and_drop_spec.js +++ b/cms/static/js/spec/utils/drag_and_drop_spec.js @@ -40,7 +40,7 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat left: $ele.offset().left }); destination = ContentDragger.findDestination($ele, 1); - expect(destination.ele).toBe($('#unit-2')); + expect(destination.ele).toEqual($('#unit-2')); expect(destination.attachMethod).toBe('before'); }); it("can drag and drop across section boundaries, with special handling for single sibling", function () { @@ -52,17 +52,17 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat left: $ele.offset().left }); destination = ContentDragger.findDestination($ele, 1); - expect(destination.ele).toBe($unit4); + expect(destination.ele).toEqual($unit4); expect(destination.attachMethod).toBe('after'); destination = ContentDragger.findDestination($ele, -1); - expect(destination.ele).toBe($unit4); + expect(destination.ele).toEqual($unit4); expect(destination.attachMethod).toBe('before'); $ele.offset({ top: $unit4.offset().top + $unit4.height() + 1, left: $ele.offset().left }); destination = ContentDragger.findDestination($ele, 0); - expect(destination.ele).toBe($unit4); + expect(destination.ele).toEqual($unit4); expect(destination.attachMethod).toBe('after'); $unit0 = $('#unit-0'); $ele.offset({ @@ -70,7 +70,7 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat left: $ele.offset().left }); destination = ContentDragger.findDestination($ele, 0); - expect(destination.ele).toBe($unit0); + expect(destination.ele).toEqual($unit0); expect(destination.attachMethod).toBe('before'); }); it("can drop before the first element, even if element being dragged is\nslightly before the first element", function () { @@ -81,7 +81,7 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat left: $ele.offset().left }); destination = ContentDragger.findDestination($ele, -1); - expect(destination.ele).toBe($('#subsection-0')); + expect(destination.ele).toEqual($('#subsection-0')); expect(destination.attachMethod).toBe('before'); }); it("can drag and drop across section boundaries, with special handling for last element", function () { @@ -92,14 +92,14 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat left: $ele.offset().left }); destination = ContentDragger.findDestination($ele, -1); - expect(destination.ele).toBe($('#unit-3')); + expect(destination.ele).toEqual($('#unit-3')); expect(destination.attachMethod).toBe('after'); $ele.offset({ top: $('#unit-3').offset().top + 4, left: $ele.offset().left }); destination = ContentDragger.findDestination($ele, -1); - expect(destination.ele).toBe($('#unit-3')); + expect(destination.ele).toEqual($('#unit-3')); expect(destination.attachMethod).toBe('before'); }); it("can drop past the last element, even if element being dragged is\nslightly before/taller then the last element", function () { @@ -110,7 +110,7 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat left: $ele.offset().left }); destination = ContentDragger.findDestination($ele, 1); - expect(destination.ele).toBe($('#subsection-4')); + expect(destination.ele).toEqual($('#subsection-4')); expect(destination.attachMethod).toBe('after'); }); it("can drag into an empty list", function () { @@ -121,7 +121,7 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat left: $ele.offset().left }); destination = ContentDragger.findDestination($ele, 1); - expect(destination.ele).toBe($('#subsection-list-3')); + expect(destination.ele).toEqual($('#subsection-list-3')); expect(destination.attachMethod).toBe('prepend'); }); it("reports a null destination on a failed drag", function () { @@ -146,8 +146,8 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat left: $ele.offset().left }); destination = ContentDragger.findDestination($ele, 1); - expect(destination.ele).toBe($('#subsection-list-2')); - expect(destination.parentList).toBe($('#subsection-2')); + expect(destination.ele).toEqual($('#subsection-list-2')); + expect(destination.parentList).toEqual($('#subsection-2')); expect(destination.attachMethod).toBe('prepend'); }); }); @@ -176,7 +176,7 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat }); describe("onDragMove", function () { beforeEach(function () { - this.redirectSpy = spyOn(window, 'scrollBy').andCallThrough(); + this.redirectSpy = spyOn(window, 'scrollBy').and.callThrough(); }); it("adds the correct CSS class to the drop destination", function () { var $ele, dragX, dragY; @@ -239,7 +239,7 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat this.reorderSpy = spyOn(ContentDragger, 'handleReorder'); }); afterEach(function () { - this.reorderSpy.reset(); + this.reorderSpy.calls.reset(); }); it("calls handleReorder on a successful drag", function () { ContentDragger.dragState.dropDestination = $('#unit-2'); @@ -279,7 +279,7 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat expect($('#subsection-1')).not.toHaveClass('expand-on-drop'); }); it("expands a collapsed element when something is dropped in it", function () { - expandElementSpy = spyOn(ContentDragger, 'expandElement').andCallThrough(); + var expandElementSpy = spyOn(ContentDragger, 'expandElement').and.callThrough(); expect(expandElementSpy).not.toHaveBeenCalled(); expect($('#subsection-2').data('ensureChildrenRendered')).not.toHaveBeenCalled(); @@ -301,8 +301,8 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat }); describe("AJAX", function () { beforeEach(function () { - this.savingSpies = spyOnConstructor(Notification, "Mini", ["show", "hide"]); - this.savingSpies.show.andReturn(this.savingSpies); + this.savingSpies = jasmine.stealth.spyOnConstructor(Notification, "Mini", ["show", "hide"]); + this.savingSpies.show.and.returnValue(this.savingSpies); this.clock = sinon.useFakeTimers(); }); afterEach(function () { @@ -327,7 +327,7 @@ define(["js/utils/drag_and_drop", "common/js/components/views/feedback_notificat expect(this.savingSpies.constructor).toHaveBeenCalled(); expect(this.savingSpies.show).toHaveBeenCalled(); expect(this.savingSpies.hide).not.toHaveBeenCalled(); - savingOptions = this.savingSpies.constructor.mostRecentCall.args[0]; + savingOptions = this.savingSpies.constructor.calls.mostRecent().args[0]; expect(savingOptions.title).toMatch(/Saving/); expect($('#unit-1')).toHaveClass('was-dropped'); expect(request.requestBody).toEqual('{"children":["fourth-unit-id","first-unit-id"]}'); diff --git a/cms/static/js/spec/utils/handle_iframe_binding_spec.js b/cms/static/js/spec/utils/handle_iframe_binding_spec.js index 5311950..cec051d 100644 --- a/cms/static/js/spec/utils/handle_iframe_binding_spec.js +++ b/cms/static/js/spec/utils/handle_iframe_binding_spec.js @@ -39,7 +39,9 @@ function ($, _, IframeBinding) { //after calling iframeBinding function: src url of iframes should have "wmode=transparent" in its querystring //and embed objects should have "wmode='transparent'" as an attribute expect(iframe_html).toContain('<iframe src="http://www.youtube.com/embed/NHd27UvY-lw?wmode=transparent"'); - expect(iframe_html).toContain('<embed wmode="transparent" type="application/x-shockwave-flash" src="http://www.youtube.com/embed/NHd27UvY-lw"'); + expect(iframe_html).toContainHtml( + '<embed wmode="transparent" type="application/x-shockwave-flash"' + + ' src="http://www.youtube.com/embed/NHd27UvY-lw"'); }); it("does not modify src url of DOM iframe if it is empty", function () { diff --git a/cms/static/js/spec/video/file_uploader_editor_spec.js b/cms/static/js/spec/video/file_uploader_editor_spec.js index c4348f4..34fcfdb 100644 --- a/cms/static/js/spec/video/file_uploader_editor_spec.js +++ b/cms/static/js/spec/video/file_uploader_editor_spec.js @@ -30,61 +30,104 @@ function ($, _, Squire) { var createPromptSpy = function (name) { var spy = jasmine.createSpyObj(name, ['constructor', 'show', 'hide']); - spy.constructor.andReturn(spy); - spy.show.andReturn(spy); - spy.extend = jasmine.createSpy().andReturn(spy.constructor); + spy.constructor.and.returnValue(spy); + spy.show.and.returnValue(spy); + spy.extend = jasmine.createSpy().and.returnValue(spy.constructor); return spy; }; - beforeEach(function () { + beforeEach(function (done) { self = this; - this.addMatchers({ - assertValueInView: function(expected) { - var value = this.actual.getValueFromEditor(); - return this.env.equals_(value, expected); + jasmine.addMatchers({ + assertValueInView: function() { + return { + compare: function (actual, expected) { + var value = actual.getValueFromEditor(), + passed = _.isEqual(value, expected); + + return { + pass: passed, + message: 'Expected ' + actual + (passed ? '' : ' not') + ' to equal ' + expected + }; + } + }; }, - assertCanUpdateView: function (expected) { - var view = this.actual, - value; - - view.setValueInEditor(expected); - value = view.getValueFromEditor(); - - return this.env.equals_(value, expected); + assertCanUpdateView: function () { + return { + compare: function (actual, expected) { + var view = actual, + value, + passed; + + view.setValueInEditor(expected); + value = view.getValueFromEditor(); + + passed = _.isEqual(value, expected); + + return { + pass: passed, + message: 'Expected ' + actual + (passed ? '' : ' not') + ' to equal ' + expected + }; + } + }; }, - assertClear: function (modelValue) { - var env = this.env, - view = this.actual, - model = view.model; - - return model.getValue() === null && - env.equals_(model.getDisplayValue(), modelValue) && - env.equals_(view.getValueFromEditor(), modelValue); + assertClear: function () { + return { + compare: function (actual, modelValue) { + var view = actual, + model = view.model, + passed; + + passed = model.getValue() === null && + _.isEqual(model.getDisplayValue(), modelValue) && + _.isEqual(view.getValueFromEditor(), modelValue); + + return { + pass: passed + }; + } + }; }, - assertUpdateModel: function (originalValue, newValue) { - var env = this.env, - view = this.actual, - model = view.model, - expectOriginal; - - view.setValueInEditor(newValue); - expectOriginal = env.equals_(model.getValue(), originalValue); - view.updateModel(); - - return expectOriginal && - env.equals_(model.getValue(), newValue); + assertUpdateModel: function () { + return { + compare: function (actual, originalValue, newValue) { + var view = actual, + model = view.model, + expectOriginal, + passed; + + view.setValueInEditor(newValue); + expectOriginal = _.isEqual(model.getValue(), originalValue); + view.updateModel(); + + passed = expectOriginal && + _.isEqual(model.getValue(), newValue); + + return { + pass: passed + }; + } + }; }, - verifyButtons: function (upload, download, index) { - var view = this.actual, - uploadBtn = view.$('.upload-setting'), - downloadBtn = view.$('.download-setting'); - - upload = upload ? uploadBtn.length : !uploadBtn.length; - download = download ? downloadBtn.length : !downloadBtn.length; - - return upload && download; + verifyButtons: function () { + return { + compare: function (actual, upload, download) { + var view = actual, + uploadBtn = view.$('.upload-setting'), + downloadBtn = view.$('.download-setting'), + passed; + + upload = upload ? uploadBtn.length : !uploadBtn.length; + download = download ? downloadBtn.length : !downloadBtn.length; + passed = upload && download; + + return { + pass: passed + }; + } + }; } }); @@ -107,22 +150,18 @@ function ($, _, Squire) { injector.mock('js/views/video/transcripts/metadata_videolist'); injector.mock('js/views/video/translations_editor'); - runs(function() { - injector.require([ + injector.require([ 'js/models/metadata', 'js/views/metadata' ], - function(MetadataModel, MetadataView) { + function (MetadataModel, MetadataView) { var model = new MetadataModel($.extend(true, {}, modelStub)); self.view = new MetadataView.FileUploader({ model: model, locator: locator }); - }); - }); - waitsFor(function() { - return self.view; - }, 'FileUploader was not created', 2000); + done(); + }); }); afterEach(function () { @@ -150,7 +189,7 @@ function ($, _, Squire) { expect(this.uploadSpies.constructor).toHaveBeenCalled(); expect(this.uploadSpies.show).toHaveBeenCalled(); - options = this.uploadSpies.constructor.mostRecentCall.args[0]; + options = this.uploadSpies.constructor.calls.mostRecent().args[0]; options.onSuccess({ 'asset': { 'url': 'http://example.org/test_3' diff --git a/cms/static/js/spec/video/transcripts/editor_spec.js b/cms/static/js/spec/video/transcripts/editor_spec.js index d489050..d2b711c 100644 --- a/cms/static/js/spec/video/transcripts/editor_spec.js +++ b/cms/static/js/spec/video/transcripts/editor_spec.js @@ -3,8 +3,7 @@ define( "jquery", "backbone", "underscore", "js/views/video/transcripts/utils", "js/views/video/transcripts/editor", "js/views/metadata", "js/models/metadata", "js/collections/metadata", - "underscore.string", "xmodule", "js/views/video/transcripts/metadata_videolist", - "jasmine-jquery" + "underscore.string", "xmodule", "js/views/video/transcripts/metadata_videolist" ], function ($, Backbone, _, Utils, Editor, MetadataView, MetadataModel, MetadataCollection, _str) { describe('Transcripts.Editor', function () { @@ -43,6 +42,13 @@ function ($, Backbone, _, Utils, Editor, MetadataView, MetadataModel, MetadataCo }, transcripts, container; + var waitsForDisplayName = function (collection) { + return jasmine.waitUntil(function () { + var displayNameValue = collection[0].getValue(); + return displayNameValue !== '' && displayNameValue !== 'video_id'; + }); + }; + beforeEach(function () { var tpl = sandbox({ 'class': 'wrapper-comp-settings basic_metadata_edit', @@ -60,7 +66,6 @@ function ($, Backbone, _, Utils, Editor, MetadataView, MetadataModel, MetadataCo }); describe('Test initialization', function () { - beforeEach(function () { spyOn(MetadataView, 'Editor'); @@ -158,27 +163,23 @@ function ($, Backbone, _, Utils, Editor, MetadataView, MetadataModel, MetadataCo }); describe('Test Advanced to Basic synchronization', function () { - it('Correct data', function () { + it('Correct data', function (done) { transcripts.syncBasicTab(metadataCollection, metadataView); - var collection = transcripts.collection.models; - waitsFor(function() { - var displayNameValue = collection[0].getValue(); - return (displayNameValue !== "" && displayNameValue != "video_id"); - }, "Defaults never loaded", 1000); - - runs(function() { - var displayNameValue = collection[0].getValue(), - videoUrlValue = collection[1].getValue(); - - expect(displayNameValue).toEqual('default'); - expect(videoUrlValue).toEqual([ - 'http://youtu.be/OEoXaMPEzfM', - 'default.mp4', - 'default.webm' - ]); - }); + waitsForDisplayName(collection) + .then(function () { + var displayNameValue = collection[0].getValue(), + videoUrlValue = collection[1].getValue(); + + expect(displayNameValue).toEqual('default'); + expect(videoUrlValue).toEqual([ + 'http://youtu.be/OEoXaMPEzfM', + 'default.mp4', + 'default.webm' + ]); + }) + .always(done); }); it('If metadataCollection is not defined', function () { @@ -219,31 +220,26 @@ function ($, Backbone, _, Utils, Editor, MetadataView, MetadataModel, MetadataCo }); describe('Test Basic to Advanced synchronization', function () { - it('Correct data', function () { + it('Correct data', function (done) { transcripts.syncAdvancedTab(metadataCollection); var collection = metadataCollection.models; - - waitsFor(function() { - var displayNameValue = collection[0].getValue(); - return (displayNameValue !== "" && displayNameValue != "video_id"); - }, "Defaults never loaded", 1000); - - runs(function() { - - var displayNameValue = collection[0].getValue(); - var subValue = collection[1].getValue(); - var html5SourcesValue = collection[2].getValue(); - var youtubeValue = collection[3].getValue(); - - expect(displayNameValue).toEqual('display value'); - expect(subValue).toEqual('default'); - expect(html5SourcesValue).toEqual([ - 'video.mp4', - 'video.webm' - ]); - expect(youtubeValue).toEqual('12345678901'); - }); + waitsForDisplayName(collection) + .then(function () { + var displayNameValue = collection[0].getValue(); + var subValue = collection[1].getValue(); + var html5SourcesValue = collection[2].getValue(); + var youtubeValue = collection[3].getValue(); + + expect(displayNameValue).toEqual('display value'); + expect(subValue).toEqual('default'); + expect(html5SourcesValue).toEqual([ + 'video.mp4', + 'video.webm' + ]); + expect(youtubeValue).toEqual('12345678901'); + }) + .always(done); }); it('metadataCollection is not defined', function () { @@ -307,8 +303,7 @@ function ($, Backbone, _, Utils, Editor, MetadataView, MetadataModel, MetadataCo transcripts.syncAdvancedTab(metadataCollection); transcripts.syncAdvancedTab(metadataCollection); transcripts.syncAdvancedTab(metadataCollection); - - expect(subModel.setValue.calls.length).toEqual(1); + expect(subModel.setValue.calls.count()).toEqual(1); }); }); diff --git a/cms/static/js/spec/video/transcripts/file_uploader_spec.js b/cms/static/js/spec/video/transcripts/file_uploader_spec.js index 59d46ea..41f159a 100644 --- a/cms/static/js/spec/video/transcripts/file_uploader_spec.js +++ b/cms/static/js/spec/video/transcripts/file_uploader_spec.js @@ -2,7 +2,7 @@ define( [ "jquery", "underscore", "js/views/video/transcripts/utils", "js/views/video/transcripts/file_uploader", - "xmodule", "jquery.form", "jasmine-jquery" + "xmodule", "jquery.form" ], function ($, _, Utils, FileUploader) { // TODO: fix TNL-559 Intermittent failures of Transcript FileUploader JS tests @@ -43,7 +43,7 @@ function ($, _, Utils, FileUploader) { .append('<div class="transcripts-file-uploader" />') .append('<a class="setting-upload" href="#">Upload</a>'); - spyOn(FileUploader.prototype, 'render').andCallThrough(); + spyOn(FileUploader.prototype, 'render').and.callThrough(); view = new FileUploader({ el: $container, @@ -61,7 +61,7 @@ function ($, _, Utils, FileUploader) { describe('Render', function () { beforeEach(function () { - spyOn(_, 'template').andCallThrough(); + spyOn(_, 'template').and.callThrough(); }); it('Template doesn\'t exist', function () { @@ -138,7 +138,7 @@ function ($, _, Utils, FileUploader) { }); it('Valid File Type - error should be hided', function () { - spyOn(view, 'checkExtValidity').andReturn(true); + spyOn(view, 'checkExtValidity').and.returnValue(true); view.$input.change(); @@ -148,7 +148,7 @@ function ($, _, Utils, FileUploader) { }); it('Invalid File Type - error should be shown', function () { - spyOn(view, 'checkExtValidity').andReturn(false); + spyOn(view, 'checkExtValidity').and.returnValue(false); view.$input.change(); @@ -189,7 +189,7 @@ function ($, _, Utils, FileUploader) { it('xhrProgressHandler', function () { var percent = 26; - spyOn($.fn, 'width').andCallThrough(); + spyOn($.fn, 'width').and.callThrough(); view.xhrProgressHandler(null, null, null, percent); expect(view.$progress.width).toHaveBeenCalledWith(percent + '%'); @@ -209,7 +209,7 @@ function ($, _, Utils, FileUploader) { view.xhrCompleteHandler(xhr); expect(view.$progress).toHaveClass('is-invisible'); - expect(view.options.messenger.render.mostRecentCall.args[0]) + expect(view.options.messenger.render.calls.mostRecent().args[0]) .toEqual('uploaded'); expect(Utils.Storage.set) .toHaveBeenCalledWith('sub', 'test'); diff --git a/cms/static/js/spec/video/transcripts/message_manager_spec.js b/cms/static/js/spec/video/transcripts/message_manager_spec.js index d929457..2324f68 100644 --- a/cms/static/js/spec/video/transcripts/message_manager_spec.js +++ b/cms/static/js/spec/video/transcripts/message_manager_spec.js @@ -2,7 +2,7 @@ define( [ "jquery", "underscore", "js/views/video/transcripts/utils", "js/views/video/transcripts/message_manager", - "js/views/video/transcripts/file_uploader", "sinon", "jasmine-jquery", + "js/views/video/transcripts/file_uploader", "sinon", "xmodule" ], function ($, _, Utils, MessageManager, FileUploader, sinon) { @@ -67,10 +67,10 @@ function ($, _, Utils, MessageManager, FileUploader, sinon) { }); // Disabled 2/6/14 after intermittent failure in master - xdescribe('Render', function () { + describe('Render', function () { beforeEach(function () { - spyOn(_,'template').andCallThrough(); + spyOn(_,'template').and.callThrough(); spyOn(fileUploader, 'render'); }); @@ -101,7 +101,7 @@ function ($, _, Utils, MessageManager, FileUploader, sinon) { beforeEach(function () { view.render('found'); spyOn(view, 'hideError'); - spyOn($.fn, 'html').andCallThrough(); + spyOn($.fn, 'html').and.callThrough(); $error = view.$el.find('.transcripts-error-message'); $buttons = view.$el.find('.wrapper-transcripts-buttons'); }); @@ -147,10 +147,10 @@ function ($, _, Utils, MessageManager, FileUploader, sinon) { $.each(handlers, function(key, value) { it(key, function () { var eventObj = jasmine.createSpyObj('event', ['preventDefault']); - spyOn($.fn, 'data').andReturn('video_id'); + spyOn($.fn, 'data').and.returnValue('video_id'); spyOn(view, 'processCommand'); view[key](eventObj); - expect(view.processCommand.mostRecentCall.args).toEqual(value); + expect(view.processCommand.calls.mostRecent().args).toEqual(value); }); }); @@ -162,7 +162,7 @@ function ($, _, Utils, MessageManager, FileUploader, sinon) { beforeEach(function () { view.render('found'); - spyOn(Utils, 'command').andCallThrough(); + spyOn(Utils, 'command').and.callThrough(); spyOn(view, 'render'); spyOn(view, 'showError'); @@ -174,35 +174,19 @@ function ($, _, Utils, MessageManager, FileUploader, sinon) { sinonXhr.restore(); }); - var assertCommand = function (config, expectFunc) { - var flag = false, - defaults = { + var assertCommand = function (config) { + var defaults = { action: 'replace', errorMessage: 'errorMessage', extraParamas: void(0) }; - args = $.extend({}, defaults, config); + var args = $.extend({}, defaults, config); - runs(function() { - view - .processCommand( - args.action, - args.errorMessage, - args.extraParamas - ) - .always(function () { flag = true; }); - }); - - waitsFor(function() { - return flag; - }, "Ajax Timeout", 750); - - - runs(expectFunc); + return view + .processCommand(args.action, args.errorMessage, args.extraParamas); }; - it('Invoke without extraParamas', function () { - + it('Invoke without extraParamas', function (done) { sinonXhr.respondWith([ 200, { "Content-Type": "application/json"}, @@ -212,9 +196,8 @@ function ($, _, Utils, MessageManager, FileUploader, sinon) { }) ]); - assertCommand( - { }, - function() { + assertCommand({}) + .then(function () { expect(Utils.command).toHaveBeenCalledWith( action, view.component_locator, @@ -222,15 +205,14 @@ function ($, _, Utils, MessageManager, FileUploader, sinon) { void(0) ); expect(view.showError).not.toHaveBeenCalled(); - expect(view.render.mostRecentCall.args[0]) + expect(view.render.calls.mostRecent().args[0]) .toEqual('found'); expect(Utils.Storage.set).toHaveBeenCalled(); - } - ); + }) + .always(done); }); - it('Invoke with extraParamas', function () { - + it('Invoke with extraParamas', function (done) { sinonXhr.respondWith([ 200, { "Content-Type": "application/json"}, @@ -242,9 +224,8 @@ function ($, _, Utils, MessageManager, FileUploader, sinon) { view.processCommand(action, errorMessage, extraParamas); - assertCommand( - { extraParamas : extraParamas }, - function () { + assertCommand({extraParamas : extraParamas}) + .then(function () { expect(Utils.command).toHaveBeenCalledWith( action, view.component_locator, @@ -254,20 +235,16 @@ function ($, _, Utils, MessageManager, FileUploader, sinon) { } ); expect(view.showError).not.toHaveBeenCalled(); - expect(view.render.mostRecentCall.args[0]) - .toEqual('found'); + expect(view.render.calls.mostRecent().args[0]).toEqual('found'); expect(Utils.Storage.set).toHaveBeenCalled(); - } - ); + }) + .always(done); }); - it('Fail', function () { - + it('Fail', function (done) { sinonXhr.respondWith([400, {}, '']); - - assertCommand( - { }, - function () { + assertCommand({}) + .then(function () { expect(Utils.command).toHaveBeenCalledWith( action, view.component_locator, @@ -277,8 +254,8 @@ function ($, _, Utils, MessageManager, FileUploader, sinon) { expect(view.showError).toHaveBeenCalled(); expect(view.render).not.toHaveBeenCalled(); expect(Utils.Storage.set).not.toHaveBeenCalled(); - } - ); + }) + .always(done); }); }); diff --git a/cms/static/js/spec/video/transcripts/utils_spec.js b/cms/static/js/spec/video/transcripts/utils_spec.js index 6658c95..14f8c92 100644 --- a/cms/static/js/spec/video/transcripts/utils_spec.js +++ b/cms/static/js/spec/video/transcripts/utils_spec.js @@ -2,7 +2,7 @@ define( [ 'jquery', 'underscore', 'js/views/video/transcripts/utils', - 'underscore.string', 'xmodule', 'jasmine-jquery' + 'underscore.string', 'xmodule' ], function ($, _, Utils, _str) { 'use strict'; diff --git a/cms/static/js/spec/video/transcripts/videolist_spec.js b/cms/static/js/spec/video/transcripts/videolist_spec.js index 51a6e00..7ea7ec5 100644 --- a/cms/static/js/spec/video/transcripts/videolist_spec.js +++ b/cms/static/js/spec/video/transcripts/videolist_spec.js @@ -5,7 +5,7 @@ define( 'js/views/video/transcripts/metadata_videolist', 'js/models/metadata', 'js/views/abstract_editor', 'common/js/spec_helpers/ajax_helpers', - 'xmodule', 'jasmine-jquery' + 'xmodule' ], function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) { 'use strict'; @@ -53,6 +53,19 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) { }), MessageManager, messenger; + + var createMockAjaxServer = function () { + var mockServer = AjaxHelpers.server( + [ + 200, + { 'Content-Type': 'application/json'}, + response + ] + ); + mockServer.autoRespond = true; + return mockServer; + }; + beforeEach(function () { var tpl = sandbox({ 'class': 'component', @@ -70,9 +83,12 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) { ).text(videoListEntryTemplate) ); - spyOn(Utils, 'command').andCallThrough(); - spyOn(abstractEditor, 'initialize').andCallThrough(); - spyOn(abstractEditor, 'render').andCallThrough(); + // create mock server + this.mockServer = createMockAjaxServer(); + + spyOn(Utils, 'command').and.callThrough(); + spyOn(abstractEditor, 'initialize').and.callThrough(); + spyOn(abstractEditor, 'render').and.callThrough(); spyOn(console, 'error'); messenger = jasmine.createSpyObj('MessageManager',[ @@ -80,7 +96,7 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) { ]); $.each(messenger, function(index, method) { - method.andReturn(messenger); + method.and.returnValue(messenger); }); MessageManager = function () { @@ -89,40 +105,54 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) { return messenger; }; - this.addMatchers({ - assertValueInView: function(expected) { - var actualValue = this.actual.getValueFromEditor(); - return this.env.equals_(actualValue, expected); - }, - assertCanUpdateView: function (expected) { - var actual = this.actual, - actualValue; - - actual.setValueInEditor(expected); - actualValue = actual.getValueFromEditor(); + jasmine.addMatchers({ + assertValueInView: function() { + return { + compare: function (actual, expected) { + var actualValue = actual.getValueFromEditor(), + passed = _.isEqual(actualValue, expected); - return this.env.equals_(actualValue, expected); + return { + pass: passed + }; + } + }; }, - assertIsCorrectVideoList: function (expected) { - var actualValue = this.actual.getVideoObjectsList(); - - return this.env.equals_(actualValue, expected); + assertCanUpdateView: function () { + return { + compare: function (actual, expected) { + var actualValue, + passed; + + actual.setValueInEditor(expected); + actualValue = actual.getValueFromEditor(); + passed = _.isEqual(actualValue, expected); + + return { + pass: passed + }; + } + }; + }, + assertIsCorrectVideoList: function () { + return { + compare: function (actual, expected) { + var actualValue = actual.getVideoObjectsList(), + passed = _.isEqual(actualValue, expected); + + return { + pass: passed + }; + } + }; } }); }); - var createMockAjaxServer = function (test) { - var mockServer = AjaxHelpers.server( - test, - [ - 200, - { 'Content-Type': 'application/json'}, - response - ] - ); - mockServer.autoRespond = true; - return mockServer; - }; + afterEach(function () { + // restore mock server + this.mockServer.restore(); + }); var createVideoListView = function () { var model = new MetadataModel(modelStub); @@ -133,37 +163,25 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) { }); }; - var waitsForResponse = function (mockServer, expectFunc, prep) { - var flag = false; - - if (prep) { - runs(prep); - } - - waitsFor(function() { + var waitsForResponse = function (mockServer) { + return jasmine.waitUntil(function () { var requests = mockServer.requests, len = requests.length; - if (len && requests[0].readyState === 4) { - flag = true; - } - - return flag; - }, 'Ajax Timeout', 750); - - runs(expectFunc); + return len && requests[0].readyState === 4; + }); }; - it('Initialize', function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(); - waitsForResponse(mockServer, function () { - expect(abstractEditor.initialize).toHaveBeenCalled(); - expect(messenger.initialize).toHaveBeenCalled(); - expect(view.component_locator).toBe(component_locator); - expect(view.$el).toHandle('input'); - }); + it('Initialize', function (done) { + var view = createVideoListView(); + waitsForResponse(this.mockServer) + .then(function () { + expect(abstractEditor.initialize).toHaveBeenCalled(); + expect(messenger.initialize).toHaveBeenCalled(); + expect(view.component_locator).toBe(component_locator); + expect(view.$el).toHandle('input'); + }).always(done); }); describe('Render', function () { @@ -178,23 +196,23 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) { expect(messenger.render).toHaveBeenCalled(); }, resetSpies = function(mockServer) { - abstractEditor.render.reset(); - Utils.command.reset(); - messenger.render.reset(); + abstractEditor.render.calls.reset(); + Utils.command.calls.reset(); + messenger.render.calls.reset(); mockServer.requests.length = 0; }; - it('is rendered in correct way', function () { - var mockServer = createMockAjaxServer(this); + it('is rendered in correct way', function (done) { createVideoListView(); - waitsForResponse(mockServer, function () { - assertToHaveBeenRendered(videoList); - }); + waitsForResponse(this.mockServer) + .then(function () { + assertToHaveBeenRendered(videoList); + }) + .always(done); }); - it('is rendered with opened extra videos bar', function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(); + it('is rendered with opened extra videos bar', function (done) { + var view = createVideoListView(); var videoListLength = [ { mode: 'youtube', @@ -215,41 +233,35 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) { } ]; - spyOn(view, 'getVideoObjectsList').andReturn(videoListLength); + spyOn(view, 'getVideoObjectsList').and.returnValue(videoListLength); spyOn(view, 'openExtraVideosBar'); - waitsForResponse( - mockServer, - function () { + resetSpies(this.mockServer); + view.render(); + + waitsForResponse(this.mockServer) + .then(function () { assertToHaveBeenRendered(videoListLength); - view.getVideoObjectsList.andReturn(videoListLength); + view.getVideoObjectsList.and.returnValue(videoListLength); expect(view.openExtraVideosBar).toHaveBeenCalled(); - }, - function () { - resetSpies(mockServer); + }) + .then(_.bind(function () { + resetSpies(this.mockServer); + view.openExtraVideosBar.calls.reset(); + view.getVideoObjectsList.and.returnValue(videoListHtml5mode); view.render(); - } - ); - waitsForResponse( - mockServer, - function () { - assertToHaveBeenRendered(videoListHtml5mode); - expect(view.openExtraVideosBar).toHaveBeenCalled(); - }, - function () { - resetSpies(mockServer); - view.openExtraVideosBar.reset(); - view.getVideoObjectsList.andReturn(videoListHtml5mode); - view.render(); - } - ); + return waitsForResponse(this.mockServer) + .then(function () { + assertToHaveBeenRendered(videoListHtml5mode); + expect(view.openExtraVideosBar).toHaveBeenCalled(); + }).then(done); + }, this)); }); - it('is rendered without opened extra videos bar', function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(), + it('is rendered without opened extra videos bar', function (done) { + var view = createVideoListView(), videoList = [ { mode: 'youtube', @@ -258,44 +270,40 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) { } ]; - spyOn(view, 'getVideoObjectsList').andReturn(videoList); + spyOn(view, 'getVideoObjectsList').and.returnValue(videoList); spyOn(view, 'closeExtraVideosBar'); - waitsForResponse( - mockServer, - function () { - assertToHaveBeenRendered(videoList); - expect(view.closeExtraVideosBar).toHaveBeenCalled(); - }, - function () { - resetSpies(mockServer); - view.render(); - } - ); - }); + resetSpies(this.mockServer); + view.render(); + waitsForResponse(this.mockServer) + .then(function () { + assertToHaveBeenRendered(videoList); + expect(view.closeExtraVideosBar).toHaveBeenCalled(); + }) + .always(done); + }); }); describe('isUniqOtherVideos', function () { - it('Unique data - return true', function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(), + it('Unique data - return true', function (done) { + var view = createVideoListView(), data = videoList.concat([{ mode: 'html5', type: 'other', video: 'pxxZrg' }]); - waitsForResponse(mockServer, function () { - var result = view.isUniqOtherVideos(data); - - expect(result).toBe(true); - }); + waitsForResponse(this.mockServer) + .then(function () { + var result = view.isUniqOtherVideos(data); + expect(result).toBe(true); + }) + .always(done); }); - it('Not Unique data - return false', function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(), + it('Not Unique data - return false', function (done) { + var view = createVideoListView(), data = [ { mode: 'html5', @@ -323,30 +331,31 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) { video: '12345678901' } ]; - waitsForResponse(mockServer, function () { - var result = view.isUniqOtherVideos(data); - expect(result).toBe(false); - }); + waitsForResponse(this.mockServer) + .then(function () { + var result = view.isUniqOtherVideos(data); + expect(result).toBe(false); + }) + .always(done); }); }); describe('isUniqVideoTypes', function () { - - it('Unique data - return true', function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(), + it('Unique data - return true', function (done) { + var view = createVideoListView(), data = videoList; - waitsForResponse(mockServer, function () { - var result = view.isUniqVideoTypes(data); - expect(result).toBe(true); - }); + waitsForResponse(this.mockServer) + .then(function () { + var result = view.isUniqVideoTypes(data); + expect(result).toBe(true); + }) + .always(done); }); - it('Not Unique data - return false', function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(), + it('Not Unique data - return false', function (done) { + var view = createVideoListView(), data = [ { mode: 'html5', @@ -369,18 +378,19 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) { video: '12345678901' } ]; - waitsForResponse(mockServer, function () { - var result = view.isUniqVideoTypes(data); - expect(result).toBe(false); - }); + waitsForResponse(this.mockServer) + .then(function () { + var result = view.isUniqVideoTypes(data); + expect(result).toBe(false); + }) + .always(done); }); }); describe('checkIsUniqVideoTypes', function () { - it('Error is shown', function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(), + it('Error is shown', function (done) { + var view = createVideoListView(), data = [ { mode: 'html5', @@ -404,125 +414,137 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) { } ]; - waitsForResponse(mockServer, function () { - var result = view.checkIsUniqVideoTypes(data); + waitsForResponse(this.mockServer) + .then(function () { + var result = view.checkIsUniqVideoTypes(data); - expect(messenger.showError).toHaveBeenCalled(); - expect(result).toBe(false); - }); + expect(messenger.showError).toHaveBeenCalled(); + expect(result).toBe(false); + }) + .always(done); }); - it('All works okay if arguments are not passed', function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(); - spyOn(view, 'getVideoObjectsList').andReturn(videoList); - waitsForResponse(mockServer, function () { - var result = view.checkIsUniqVideoTypes(); + it('All works okay if arguments are not passed', function (done) { + var view = createVideoListView(); + spyOn(view, 'getVideoObjectsList').and.returnValue(videoList); - expect(view.getVideoObjectsList).toHaveBeenCalled(); - expect(messenger.showError).not.toHaveBeenCalled(); - expect(result).toBe(true); - }); + waitsForResponse(this.mockServer) + .then(function () { + var result = view.checkIsUniqVideoTypes(); + + expect(view.getVideoObjectsList).toHaveBeenCalled(); + expect(messenger.showError).not.toHaveBeenCalled(); + expect(result).toBe(true); + }) + .always(done); }); }); describe('checkValidity', function () { - it('Error message is shown', function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(); - spyOn(view, 'checkIsUniqVideoTypes').andReturn(true); - waitsForResponse(mockServer, function () { - var data = { mode: 'incorrect' }, + it('Error message is shown', function (done) { + var view = createVideoListView(); + spyOn(view, 'checkIsUniqVideoTypes').and.returnValue(true); + + waitsForResponse(this.mockServer) + .then(function () { + var data = {mode: 'incorrect'}, result = view.checkValidity(data, true); - expect(messenger.showError).toHaveBeenCalled(); - expect(view.checkIsUniqVideoTypes).toHaveBeenCalled(); - expect(result).toBe(false); - }); + expect(messenger.showError).toHaveBeenCalled(); + expect(view.checkIsUniqVideoTypes).toHaveBeenCalled(); + expect(result).toBe(false); + }) + .always(done); }); - it('Error message is shown when flag is not passed', function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(); - spyOn(view, 'checkIsUniqVideoTypes').andReturn(true); - waitsForResponse(mockServer, function () { - var data = { mode: 'incorrect' }, + it('Error message is shown when flag is not passed', function (done) { + var view = createVideoListView(); + spyOn(view, 'checkIsUniqVideoTypes').and.returnValue(true); + + waitsForResponse(this.mockServer) + .then(function () { + var data = {mode: 'incorrect'}, result = view.checkValidity(data); - expect(messenger.showError).not.toHaveBeenCalled(); - expect(view.checkIsUniqVideoTypes).toHaveBeenCalled(); - expect(result).toBe(true); - }); + expect(messenger.showError).not.toHaveBeenCalled(); + expect(view.checkIsUniqVideoTypes).toHaveBeenCalled(); + expect(result).toBe(true); + }).always(done); }); - it('All works okay if correct data is passed', function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(); - spyOn(view, 'checkIsUniqVideoTypes').andReturn(true); - waitsForResponse(mockServer, function () { - var data = videoList, + it('All works okay if correct data is passed', function (done) { + var view = createVideoListView(); + spyOn(view, 'checkIsUniqVideoTypes').and.returnValue(true); + + waitsForResponse(this.mockServer) + .then(function () { + var data = videoList, result = view.checkValidity(data); - expect(messenger.showError).not.toHaveBeenCalled(); - expect(view.checkIsUniqVideoTypes).toHaveBeenCalled(); - expect(result).toBe(true); - }); + expect(messenger.showError).not.toHaveBeenCalled(); + expect(view.checkIsUniqVideoTypes).toHaveBeenCalled(); + expect(result).toBe(true); + }) + .always(done); }); }); - it('openExtraVideosBar', function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(); - waitsForResponse(mockServer, function () { - view.$extraVideosBar.removeClass('is-visible'); - - view.openExtraVideosBar(); - expect(view.$extraVideosBar).toHaveClass('is-visible'); - }); + it('openExtraVideosBar', function (done) { + var view = createVideoListView(); + waitsForResponse(this.mockServer) + .then(function () { + view.$extraVideosBar.removeClass('is-visible'); + view.openExtraVideosBar(); + expect(view.$extraVideosBar).toHaveClass('is-visible'); + }) + .always(done); }); - it('closeExtraVideosBar', function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(); - waitsForResponse(mockServer, function () { - view.$extraVideosBar.addClass('is-visible'); - view.closeExtraVideosBar(); + it('closeExtraVideosBar', function (done) { + var view = createVideoListView(); + waitsForResponse(this.mockServer) + .then(function () { + view.$extraVideosBar.addClass('is-visible'); + view.closeExtraVideosBar(); - expect(view.$extraVideosBar).not.toHaveClass('is-visible'); - }); + expect(view.$extraVideosBar).not.toHaveClass('is-visible'); + }) + .always(done); }); - it('toggleExtraVideosBar', function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(); - waitsForResponse(mockServer, function () { - view.$extraVideosBar.addClass('is-visible'); - view.toggleExtraVideosBar(); - expect(view.$extraVideosBar).not.toHaveClass('is-visible'); - view.toggleExtraVideosBar(); - expect(view.$extraVideosBar).toHaveClass('is-visible'); - }); + it('toggleExtraVideosBar', function (done) { + var view = createVideoListView(); + waitsForResponse(this.mockServer) + .then(function () { + view.$extraVideosBar.addClass('is-visible'); + view.toggleExtraVideosBar(); + expect(view.$extraVideosBar).not.toHaveClass('is-visible'); + view.toggleExtraVideosBar(); + expect(view.$extraVideosBar).toHaveClass('is-visible'); + }) + .always(done); }); - it('getValueFromEditor', function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(); - waitsForResponse(mockServer, function () { - expect(view).assertValueInView(modelStub.value); - }); + it('getValueFromEditor', function (done) { + var view = createVideoListView(); + waitsForResponse(this.mockServer) + .then(function () { + expect(view).assertValueInView(modelStub.value); + }) + .always(done); }); - it('setValueInEditor', function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(); - waitsForResponse(mockServer, function () { - expect(view).assertCanUpdateView(['abc.mp4']); - }); + it('setValueInEditor', function (done) { + var view = createVideoListView(); + waitsForResponse(this.mockServer) + .then(function () { + expect(view).assertCanUpdateView(['abc.mp4']); + }) + .always(done); }); - it('getVideoObjectsList', function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(); + it('getVideoObjectsList', function (done) { + var view = createVideoListView(); var value = [ { mode: 'youtube', @@ -541,36 +563,39 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) { } ]; - waitsForResponse(mockServer, function () { - view.setValueInEditor([ - 'http://youtu.be/12345678901', - 'video.mp4', - 'http://goo.gl/pxxZrg', - 'video' - ]); - expect(view).assertIsCorrectVideoList(value); - }); + waitsForResponse(this.mockServer) + .then(function () { + view.setValueInEditor([ + 'http://youtu.be/12345678901', + 'video.mp4', + 'http://goo.gl/pxxZrg', + 'video' + ]); + expect(view).assertIsCorrectVideoList(value); + }) + .always(done); }); describe('getPlaceholders', function () { - it('All works okay if empty values are passed', function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(), + it('All works okay if empty values are passed', function (done) { + var view = createVideoListView(), defaultPlaceholders = view.placeholders; - waitsForResponse(mockServer, function () { - var result = view.getPlaceholders([]), - expectedResult = _.values(defaultPlaceholders).reverse(); - expect(result).toEqual(expectedResult); - }); + waitsForResponse(this.mockServer) + .then(function () { + var result = view.getPlaceholders([]), + expectedResult = _.values(defaultPlaceholders).reverse(); + + expect(result).toEqual(expectedResult); + }) + .always(done); }); it('On filling less than 3 fields, remaining fields should have ' + 'placeholders for video types that were not filled yet', - function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(), + function (done) { + var view = createVideoListView(), defaultPlaceholders = view.placeholders; var dataDict = { youtube: { @@ -598,14 +623,17 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) { ] } }; - defaultPlaceholders = view.placeholders; - waitsForResponse(mockServer, function () { - $.each(dataDict, function(index, val) { - var result = view.getPlaceholders(val.value); - - expect(result).toEqual(val.expectedResult); - }); - }); + + defaultPlaceholders = view.placeholders; + waitsForResponse(this.mockServer) + .then(function () { + $.each(dataDict, function (index, val) { + var result = view.getPlaceholders(val.value); + + expect(result).toEqual(val.expectedResult); + }); + }) + .always(done); } ); }); @@ -614,9 +642,9 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) { var eventObject; var resetSpies = function (view) { - messenger.hideError.reset(); - view.updateModel.reset(); - view.closeExtraVideosBar.reset(); + messenger.hideError.calls.reset(); + view.updateModel.calls.reset(); + view.closeExtraVideosBar.calls.reset(); }; var setUp = function (view) { @@ -628,100 +656,104 @@ function ($, _, Utils, VideoList, MetadataModel, AbstractEditor, AjaxHelpers) { spyOn($.fn, 'hasClass'); spyOn($.fn, 'addClass'); spyOn($.fn, 'removeClass'); - spyOn($.fn, 'prop').andCallThrough(); + spyOn($.fn, 'prop').and.callThrough(); spyOn(_, 'isEqual'); resetSpies(view); }; it('Field has invalid value - nothing should happen', - function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(); + function (done) { + var view = createVideoListView(); setUp(view); - $.fn.hasClass.andReturn(false); - view.checkValidity.andReturn(false); - - waitsForResponse(mockServer, function () { - view.inputHandler(eventObject); - expect(messenger.hideError).not.toHaveBeenCalled(); - expect(view.updateModel).not.toHaveBeenCalled(); - expect(view.closeExtraVideosBar).not.toHaveBeenCalled(); - expect($.fn.prop).toHaveBeenCalledWith( - 'disabled', true - ); - expect($.fn.addClass).toHaveBeenCalledWith( - 'is-disabled' - ); - }); + $.fn.hasClass.and.returnValue(false); + view.checkValidity.and.returnValue(false); + + waitsForResponse(this.mockServer) + .then(function () { + view.inputHandler(eventObject); + expect(messenger.hideError).not.toHaveBeenCalled(); + expect(view.updateModel).not.toHaveBeenCalled(); + expect(view.closeExtraVideosBar).not.toHaveBeenCalled(); + expect($.fn.prop).toHaveBeenCalledWith( + 'disabled', true + ); + expect($.fn.addClass).toHaveBeenCalledWith( + 'is-disabled' + ); + }) + .always(done); } ); it('Main field has invalid value - extra Videos Bar is closed', - function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(); + function (done) { + var view = createVideoListView(); setUp(view); - $.fn.hasClass.andReturn(true); - view.checkValidity.andReturn(false); - - waitsForResponse(mockServer, function () { - view.inputHandler(eventObject); - expect(messenger.hideError).not.toHaveBeenCalled(); - expect(view.updateModel).not.toHaveBeenCalled(); - expect(view.closeExtraVideosBar).toHaveBeenCalled(); - expect($.fn.prop).toHaveBeenCalledWith( - 'disabled', true - ); - expect($.fn.addClass).toHaveBeenCalledWith( - 'is-disabled' - ); - }); + $.fn.hasClass.and.returnValue(true); + view.checkValidity.and.returnValue(false); + + waitsForResponse(this.mockServer) + .then(function () { + view.inputHandler(eventObject); + expect(messenger.hideError).not.toHaveBeenCalled(); + expect(view.updateModel).not.toHaveBeenCalled(); + expect(view.closeExtraVideosBar).toHaveBeenCalled(); + expect($.fn.prop).toHaveBeenCalledWith( + 'disabled', true + ); + expect($.fn.addClass).toHaveBeenCalledWith( + 'is-disabled' + ); + }) + .always(done); } ); it('Model is updated if value is valid', - function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(); + function (done) { + var view = createVideoListView(); setUp(view); - view.checkValidity.andReturn(true); - _.isEqual.andReturn(false); - - waitsForResponse(mockServer, function () { - view.inputHandler(eventObject); - expect(messenger.hideError).not.toHaveBeenCalled(); - expect(view.updateModel).toHaveBeenCalled(); - expect(view.closeExtraVideosBar).not.toHaveBeenCalled(); - expect($.fn.prop).toHaveBeenCalledWith( - 'disabled', false - ); - expect($.fn.removeClass).toHaveBeenCalledWith( - 'is-disabled' - ); - }); + view.checkValidity.and.returnValue(true); + _.isEqual.and.returnValue(false); + + waitsForResponse(this.mockServer) + .then(function () { + view.inputHandler(eventObject); + expect(messenger.hideError).not.toHaveBeenCalled(); + expect(view.updateModel).toHaveBeenCalled(); + expect(view.closeExtraVideosBar).not.toHaveBeenCalled(); + expect($.fn.prop).toHaveBeenCalledWith( + 'disabled', false + ); + expect($.fn.removeClass).toHaveBeenCalledWith( + 'is-disabled' + ); + }) + .always(done); } ); it('Corner case: Error is hided', - function () { - var mockServer = createMockAjaxServer(this), - view = createVideoListView(); + function (done) { + var view = createVideoListView(); setUp(view); - view.checkValidity.andReturn(true); - _.isEqual.andReturn(true); - waitsForResponse(mockServer, function () { - view.inputHandler(eventObject); - expect(messenger.hideError).toHaveBeenCalled(); - expect(view.updateModel).not.toHaveBeenCalled(); - expect(view.closeExtraVideosBar).not.toHaveBeenCalled(); - expect($.fn.prop).toHaveBeenCalledWith( - 'disabled', false - ); - expect($.fn.removeClass).toHaveBeenCalledWith( - 'is-disabled' - ); - }); + view.checkValidity.and.returnValue(true); + _.isEqual.and.returnValue(true); + waitsForResponse(this.mockServer) + .then(function () { + view.inputHandler(eventObject); + expect(messenger.hideError).toHaveBeenCalled(); + expect(view.updateModel).not.toHaveBeenCalled(); + expect(view.closeExtraVideosBar).not.toHaveBeenCalled(); + expect($.fn.prop).toHaveBeenCalledWith( + 'disabled', false + ); + expect($.fn.removeClass).toHaveBeenCalledWith( + 'is-disabled' + ); + }) + .always(done); } ); diff --git a/cms/static/js/spec/video/translations_editor_spec.js b/cms/static/js/spec/video/translations_editor_spec.js index 2bc212d..b86cc91 100644 --- a/cms/static/js/spec/video/translations_editor_spec.js +++ b/cms/static/js/spec/video/translations_editor_spec.js @@ -45,82 +45,133 @@ function ($, _, Squire) { var createPromptSpy = function (name) { var spy = jasmine.createSpyObj(name, ['constructor', 'show', 'hide']); - spy.constructor.andReturn(spy); - spy.show.andReturn(spy); - spy.extend = jasmine.createSpy().andReturn(spy.constructor); + spy.constructor.and.returnValue(spy); + spy.show.and.returnValue(spy); + spy.extend = jasmine.createSpy().and.returnValue(spy.constructor); return spy; }; - beforeEach(function () { + beforeEach(function (done) { self = this; - this.addMatchers({ - assertValueInView: function(expected) { - var value = this.actual.getValueFromEditor(); - return this.env.equals_(value, expected); + jasmine.addMatchers({ + assertValueInView: function() { + return { + compare: function (actual, expected) { + var value = actual.getValueFromEditor(); + var passed = _.isEqual(value, expected); + + return { + pass: passed, + message: 'Expected ' + actual + (passed ? '' : ' not') + ' to equal ' + expected + }; + } + }; }, - assertCanUpdateView: function (expected) { - var view = this.actual, - value; - - view.setValueInEditor(expected); - value = view.getValueFromEditor(); - - return this.env.equals_(value, expected); + assertCanUpdateView: function () { + return { + compare: function (actual, expected) { + var view = actual, + value, + passed; + + view.setValueInEditor(expected); + value = view.getValueFromEditor(); + passed = _.isEqual(value, expected); + + return { + pass: passed, + message: 'Expected ' + actual + (passed ? '' : ' not') + ' to equal ' + expected + }; + } + }; }, - assertClear: function (modelValue) { - var env = this.env, - view = this.actual, - model = view.model; - - return model.getValue() === null && - env.equals_(model.getDisplayValue(), modelValue) && - env.equals_(view.getValueFromEditor(), modelValue); + assertClear: function () { + return { + compare: function (actual, modelValue) { + var view = actual, + model = view.model, + passed; + + passed = model.getValue() === null && + _.isEqual(model.getDisplayValue(), modelValue) && + _.isEqual(view.getValueFromEditor(), modelValue); + + return { + pass: passed + }; + } + }; }, - assertUpdateModel: function (originalValue, newValue) { - var env = this.env, - view = this.actual, - model = view.model, - expectOriginal; - - view.setValueInEditor(newValue); - expectOriginal = env.equals_(model.getValue(), originalValue); - view.updateModel(); - - return expectOriginal && - env.equals_(model.getValue(), newValue); + assertUpdateModel: function () { + return { + compare: function (actual, originalValue, newValue) { + var view = actual, + model = view.model, + expectOriginal, + passed; + + view.setValueInEditor(newValue); + expectOriginal = _.isEqual(model.getValue(), originalValue); + view.updateModel(); + + passed = expectOriginal && + _.isEqual(model.getValue(), newValue); + + return { + pass: passed + }; + } + }; }, - verifyKeysUnique: function (initial, expected, testData) { - var env = this.env, - view = this.actual, - item, value; - - view.setValueInEditor(initial); - view.updateModel(); - view.$el.find('.create-setting').click(); - item = view.$el.find('.list-settings-item').last(); - item.find('select').val(testData.key); - item.find('input:hidden').val(testData.value); - value = view.getValueFromEditor(); - - return env.equals_(value, expected); + verifyKeysUnique: function () { + return { + compare: function (actual, initial, expected, testData) { + var view = this.actual, + item, + value, + passed; + + view.setValueInEditor(initial); + view.updateModel(); + view.$el.find('.create-setting').click(); + item = view.$el.find('.list-settings-item').last(); + item.find('select').val(testData.key); + item.find('input:hidden').val(testData.value); + value = view.getValueFromEditor(); + + passed = _.isEqual(value, expected); + + return { + pass: passed + }; + } + }; }, - verifyButtons: function (upload, download, remove, index) { - var view = this.actual, - items = view.$el.find('.list-settings-item'), - item = index ? items.eq(index) : items.last(), - uploadBtn = item.find('.upload-setting'), - downloadBtn = item.find('.download-setting'), - removeBtn = item.find('.remove-setting'); - - - upload = upload ? uploadBtn.length : !uploadBtn.length; - download = download ? downloadBtn.length : !downloadBtn.length; - remove = remove ? removeBtn.length : !removeBtn.length; - - return upload && download && remove; - + verifyButtons: function () { + return { + compare: function (actual, upload, download, remove, index) { + var view = this.actual, + items = view.$el.find('.list-settings-item'), + item = index ? items.eq(index) : items.last(), + uploadBtn = item.find('.upload-setting'), + downloadBtn = item.find('.download-setting'), + removeBtn = item.find('.remove-setting'), + passed; + + + upload = upload ? uploadBtn.length : !uploadBtn.length; + download = download ? downloadBtn.length : !downloadBtn.length; + remove = remove ? removeBtn.length : !removeBtn.length; + + passed = upload && download && remove; + + return { + pass: passed + }; + } + }; } }); @@ -141,19 +192,15 @@ function ($, _, Squire) { return self.uploadSpies; }); - runs(function() { - injector.require([ + injector.require([ 'js/models/metadata', 'js/views/video/translations_editor' ], - function(MetadataModel, Translations) { + function (MetadataModel, Translations) { var model = new MetadataModel($.extend(true, {}, modelStub)); self.view = new Translations({model: model}); - }); - }); - waitsFor(function() { - return self.view; - }, 'VideoTranslations was not created', 1000); + done(); + }); }); afterEach(function () { @@ -198,7 +245,7 @@ function ($, _, Squire) { expect(this.uploadSpies.constructor).toHaveBeenCalled(); expect(this.uploadSpies.show).toHaveBeenCalled(); - options = this.uploadSpies.constructor.mostRecentCall.args[0]; + options = this.uploadSpies.constructor.calls.mostRecent().args[0]; options.onSuccess({'filename': 'zh.srt'}); expect(this.view).verifyButtons(true, true, true); diff --git a/cms/static/js/spec/views/active_video_upload_list_spec.js b/cms/static/js/spec/views/active_video_upload_list_spec.js index bd1b7fd..1b985e2 100644 --- a/cms/static/js/spec/views/active_video_upload_list_spec.js +++ b/cms/static/js/spec/views/active_video_upload_list_spec.js @@ -1,5 +1,11 @@ define( - ["jquery", "js/models/active_video_upload", "js/views/active_video_upload_list", "common/js/spec_helpers/template_helpers", "mock-ajax", "jasmine-jquery"], + [ + "jquery", + "js/models/active_video_upload", + "js/views/active_video_upload_list", + "common/js/spec_helpers/template_helpers", + "mock-ajax" + ], function($, ActiveVideoUpload, ActiveVideoUploadListView, TemplateHelpers) { "use strict"; var concurrentUploadLimit = 2; @@ -16,8 +22,7 @@ define( uploadButton: this.uploadButton }); this.view.render(); - jasmine.Ajax.useMock(); - clearAjaxRequests(); + jasmine.Ajax.install(); this.globalAjaxError = jasmine.createSpy(); $(document).ajaxError(this.globalAjaxError); }); @@ -25,15 +30,16 @@ define( // Remove window unload handler triggered by the upload requests afterEach(function() { $(window).off("beforeunload"); + jasmine.Ajax.uninstall(); }); it("should trigger file selection when either the upload button or the drop zone is clicked", function() { var clickSpy = jasmine.createSpy(); - clickSpy.andCallFake(function(event) { event.preventDefault(); }); + clickSpy.and.callFake(function(event) { event.preventDefault(); }); this.view.$(".js-file-input").on("click", clickSpy); this.view.$(".file-drop-area").click(); expect(clickSpy).toHaveBeenCalled(); - clickSpy.reset(); + clickSpy.calls.reset(); this.uploadButton.click(); expect(clickSpy).toHaveBeenCalled(); }); @@ -47,17 +53,16 @@ define( }; var getSentRequests = function() { - return _.filter( - ajaxRequests, - function(request) { return request.readyState > 0; } - ); + return jasmine.Ajax.requests.filter(function (request) { + return request.readyState > 0; + }); }; _.each( [ {desc: "a single file", numFiles: 1}, {desc: "multiple files", numFiles: concurrentUploadLimit}, - {desc: "more files than upload limit", numFiles: concurrentUploadLimit + 1}, + {desc: "more files than upload limit", numFiles: concurrentUploadLimit + 1} ], function(caseInfo) { var fileNames = _.map( @@ -71,7 +76,7 @@ define( // security reasons, so we must mock the access mechanism // that jQuery-File-Upload uses to retrieve it. var realProp = $.prop; - spyOn($, "prop").andCallFake(function(el, propName) { + spyOn($, "prop").and.callFake(function(el, propName) { if (arguments.length == 2 && propName == "files") { return _.map( fileNames, @@ -82,7 +87,7 @@ define( } }); this.view.$(".js-file-input").change(); - this.request = mostRecentAjaxRequest(); + this.request = jasmine.Ajax.requests.mostRecent(); }); it("should trigger the correct request", function() { @@ -99,14 +104,14 @@ define( }); it("should trigger the global AJAX error handler on server error", function() { - this.request.response({status: 500}); + this.request.respondWith({status: 500}); expect(this.globalAjaxError).toHaveBeenCalled(); }); describe("and successful server response", function() { beforeEach(function() { - clearAjaxRequests(); - this.request.response({ + jasmine.Ajax.requests.reset(); + this.request.respondWith({ status: 200, responseText: JSON.stringify({ files: _.map( @@ -141,7 +146,6 @@ define( }); it("should display upload status and progress", function() { - var spec = this; expect(this.$uploadElems.length).toEqual(caseInfo.numFiles); this.$uploadElems.each(function(i, uploadElem) { var $uploadElem = $(uploadElem); @@ -154,7 +158,7 @@ define( ActiveVideoUpload.STATUS_QUEUED : ActiveVideoUpload.STATUS_UPLOADING ); - expect($uploadElem.find(".video-detail-progress").attr("value")).toEqual(0); + expect($uploadElem.find(".video-detail-progress").val()).toEqual(0); expect($uploadElem).not.toHaveClass("success"); expect($uploadElem).not.toHaveClass("error"); expect($uploadElem.hasClass("queued")).toEqual(queued); @@ -187,12 +191,12 @@ define( progressValue: 0, presentClass: "error", absentClass: "success" - }, + } ], function(subCaseInfo) { describe("and upload " + subCaseInfo.desc, function() { beforeEach(function() { - getSentRequests()[0].response({status: subCaseInfo.responseStatus}); + getSentRequests()[0].respondWith({status: subCaseInfo.responseStatus}); }); it("should update status and progress", function() { @@ -202,7 +206,7 @@ define( subCaseInfo.statusText ); expect( - $uploadElem.find(".video-detail-progress").attr("value") + $uploadElem.find(".video-detail-progress").val() ).toEqual(subCaseInfo.progressValue); expect($uploadElem).toHaveClass(subCaseInfo.presentClass); expect($uploadElem).not.toHaveClass(subCaseInfo.absentClass); diff --git a/cms/static/js/spec/views/assets_spec.js b/cms/static/js/spec/views/assets_spec.js index 87c5006..921c2b7 100644 --- a/cms/static/js/spec/views/assets_spec.js +++ b/cms/static/js/spec/views/assets_spec.js @@ -16,7 +16,7 @@ define([ "jquery", "common/js/spec_helpers/ajax_helpers", "URI", "js/views/asset appendSetFixtures(uploadModalTpl); appendSetFixtures(sandbox({ id: "asset_table_body" })); - spyOn($.fn, "fileupload").andReturn(""); + spyOn($.fn, "fileupload").and.returnValue(""); var collection = new AssetCollection(); collection.url = "assets-url"; @@ -181,7 +181,7 @@ define([ "jquery", "common/js/spec_helpers/ajax_helpers", "URI", "js/views/asset it('uploads file properly', function () { var requests = setup.call(this); expect(assetsView).toBeDefined(); - spyOn(assetsView, "addAsset").andCallFake(function () { + spyOn(assetsView, "addAsset").and.callFake(function () { assetsView.collection.add(mockAssetUploadResponse.asset); assetsView.pagingView.renderPageItems(); assetsView.pagingView.setPage(0); diff --git a/cms/static/js/spec/views/baseview_spec.js b/cms/static/js/spec/views/baseview_spec.js index 4d88992..b88a91c 100644 --- a/cms/static/js/spec/views/baseview_spec.js +++ b/cms/static/js/spec/views/baseview_spec.js @@ -13,8 +13,8 @@ define(["jquery", "underscore", "js/views/baseview", "js/utils/handle_iframe_bin spyOn(baseViewPrototype, 'initialize'); spyOn(baseViewPrototype, 'beforeRender'); - spyOn(baseViewPrototype, 'render').andCallThrough(); - spyOn(baseViewPrototype, 'afterRender').andCallThrough(); + spyOn(baseViewPrototype, 'render').and.callThrough(); + spyOn(baseViewPrototype, 'afterRender').and.callThrough(); }); afterEach(function () { diff --git a/cms/static/js/spec/views/group_configuration_spec.js b/cms/static/js/spec/views/group_configuration_spec.js index 9309e04..b049f2f 100644 --- a/cms/static/js/spec/views/group_configuration_spec.js +++ b/cms/static/js/spec/views/group_configuration_spec.js @@ -125,7 +125,7 @@ define([ ViewHelpers.verifyNotificationShowing(notificationSpy, /Deleting/); expect($(listItemView)).toExist(); }; - var assertCannotDeleteUsed = function (that, toolTipText, warningText){ + var assertCannotDeleteUsed = function (that, toolTipText, warningText) { setUsageInfo(that.model); that.view.render(); expect(that.view.$(SELECTORS.note)).toHaveAttr( @@ -153,36 +153,69 @@ define([ revision: 'course_rev' }); - this.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; - } + jasmine.addMatchers({ + toContainText: function() { + return { + compare: function (actual, text) { + var trimmedText = $.trim(actual.text()), + passed; + + if (text && $.isFunction(text.test)) { + passed = text.test(trimmedText); + } else { + passed = trimmedText.indexOf(text) !== -1; + } + + return { + pass: passed + }; + } + }; }, - toBeCorrectValuesInInputs: function (values) { - var expected = { - name: this.actual.$(SELECTORS.inputName).val(), - description: this.actual - .$(SELECTORS.inputDescription).val() + toBeCorrectValuesInInputs: function () { + return { + compare: function (actual, values) { + var expected = { + name: actual.$(SELECTORS.inputName).val(), + description: actual + .$(SELECTORS.inputDescription).val() + }; + + var passed = _.isEqual(values, expected); + + return { + pass: passed + }; + } }; - - return _.isEqual(values, expected); }, - toBeCorrectValuesInModel: function (values) { - return _.every(values, function (value, key) { - return this.actual.get(key) === value; - }.bind(this)); + toBeCorrectValuesInModel: function () { + return { + compare: function (actual, values) { + var passed = _.every(values, function (value, key) { + return actual.get(key) === value; + }.bind(this)); + + return { + pass: passed + }; + } + }; }, - toHaveDefaultNames: function (values) { - var actualValues = $.map(this.actual, function (item) { - return $(item).val(); - }); - - return _.isEqual(actualValues, values); + toHaveDefaultNames: function () { + return { + compare: function (actual, values) { + var actualValues = $.map(actual, function (item) { + return $(item).val(); + }); + + var passed = _.isEqual(actualValues, values); + + return { + pass: passed + }; + } + }; } }); }); @@ -389,7 +422,7 @@ define([ groups = this.model.get('groups'); expect(groups.length).toBe(3); expect(groups.at(2).get('name')).toBe('Group C'); - expect(this.view.$el).not.toExist(); + expect(this.view.$el).not.toBeInDOM(); }); it('does not hide saving message if failure', function() { @@ -421,7 +454,7 @@ define([ }); it('should be removed on cancel if it is a new item', function() { - spyOn(this.model, 'isNew').andReturn(true); + spyOn(this.model, 'isNew').and.returnValue(true); setValuesToInputs(this.view, { inputName: 'New Configuration', inputDescription: 'New Description' @@ -454,18 +487,23 @@ define([ name: 'New Configuration' }); // Error message disappear - expect(this.view.$(SELECTORS.errorMessage)).not.toExist(); + expect(this.view.$(SELECTORS.errorMessage)).not.toBeInDOM(); AjaxHelpers.expectNoRequests(requests); }); - it('should have appropriate class names on focus/blur', function () { + it('should have appropriate class names on focus/blur', function (done) { var groupInput = this.view.$(SELECTORS.inputGroupName).first(), groupFields = this.view.$(SELECTORS.groupFields); groupInput.focus(); - expect(groupFields).toHaveClass('is-focused'); - groupInput.blur(); - expect(groupFields).not.toHaveClass('is-focused'); + jasmine.waitUntil(function() { + return groupFields.hasClass('is-focused'); + }).then(function () { + groupInput.blur(); + jasmine.waitUntil(function() { + return !groupFields.hasClass('is-focused'); + }).then(done); + }); }); describe('removes all newly created groups on cancel', function () { @@ -957,13 +995,13 @@ define([ expect(this.model).toBeCorrectValuesInModel({ name: 'New Content Group' }); - expect(this.view.$el).not.toExist(); + expect(this.view.$el).not.toBeInDOM(); }); it('does not hide saving message if failure', function() { var requests = AjaxHelpers.requests(this), notificationSpy = ViewHelpers.createNotificationSpy(); - this.view.$(SELECTORS.inputName).val('New Content Group') + this.view.$(SELECTORS.inputName).val('New Content Group'); ViewHelpers.submitAndVerifyFormError(this.view, requests, notificationSpy) }); diff --git a/cms/static/js/spec/views/login_studio_spec.js b/cms/static/js/spec/views/login_studio_spec.js index 2fb44c2..b5c752f 100644 --- a/cms/static/js/spec/views/login_studio_spec.js +++ b/cms/static/js/spec/views/login_studio_spec.js @@ -12,7 +12,7 @@ function($, LoginFactory, AjaxHelpers, ViewUtils) { }); it('disable the submit button once it is clicked', function() { - spyOn(ViewUtils, 'redirect').andCallFake(function(){}); + spyOn(ViewUtils, 'redirect').and.callFake(function(){}); var requests = AjaxHelpers.requests(this); expect(submitButton).not.toHaveClass('is-disabled'); submitButton.click(); diff --git a/cms/static/js/spec/views/modals/base_modal_spec.js b/cms/static/js/spec/views/modals/base_modal_spec.js index 6d752ee..5878ce0 100644 --- a/cms/static/js/spec/views/modals/base_modal_spec.js +++ b/cms/static/js/spec/views/modals/base_modal_spec.js @@ -31,14 +31,13 @@ define(["jquery", "underscore", "js/views/modals/base_modal", "js/spec_helpers/m expect(ModelHelpers.isShowingModal(modal)).toBeTruthy(); }); - it('sends focus to the modal window after show is called', function() { + it('sends focus to the modal window after show is called', function(done) { showMockModal(); - waitsFor(function () { - // This is the implementation of "toBeFocused". However, simply calling that method - // with no wait seems to be flaky. + + jasmine.waitUntil(function() { var modalWindow = ModelHelpers.getModalWindow(modal); - return $(modalWindow)[0] === $(modalWindow)[0].ownerDocument.activeElement; - }, 'Modal Window did not get focus', 5000); + return ($(modalWindow)[0] === $(modalWindow)[0].ownerDocument.activeElement); + }).then(done); }); it('is removed after hide is called', function () { diff --git a/cms/static/js/spec/views/modals/validation_error_modal_spec.js b/cms/static/js/spec/views/modals/validation_error_modal_spec.js index 7a722fd..605abad 100644 --- a/cms/static/js/spec/views/modals/validation_error_modal_spec.js +++ b/cms/static/js/spec/views/modals/validation_error_modal_spec.js @@ -51,7 +51,7 @@ define(['jquery', 'underscore', 'js/spec_helpers/validation_helpers', 'js/views/ ValidationHelpers.checkErrorContents(modal, errorObjects); }); - it('run callback when undo changes button is clicked', function () { + it('run callback when undo changes button is clicked', function (done) { var errorObjects = [ { model: {display_name: 'test_attribute1'}, @@ -64,7 +64,7 @@ define(['jquery', 'underscore', 'js/spec_helpers/validation_helpers', 'js/views/ ]; var callback = function() { - return true; + done(); }; // Show Modal and click undo changes @@ -72,15 +72,8 @@ define(['jquery', 'underscore', 'js/spec_helpers/validation_helpers', 'js/views/ expect(ValidationHelpers.isShowingModal(modal)).toBeTruthy(); ValidationHelpers.undoChanges(modal); - // Wait for the callback to be fired - waitsFor(function () { - return callback(); - }, 'the callback to be called', 5000); - // After checking callback fire, check modal hide - runs(function () { - expect(ValidationHelpers.isShowingModal(modal)).toBe(false); - }); + expect(ValidationHelpers.isShowingModal(modal)).toBe(false); }); }); }); diff --git a/cms/static/js/spec/views/paged_container_spec.js b/cms/static/js/spec/views/paged_container_spec.js index fd55c3e..282ae33 100644 --- a/cms/static/js/spec/views/paged_container_spec.js +++ b/cms/static/js/spec/views/paged_container_spec.js @@ -74,7 +74,10 @@ define(["jquery", "underscore", "common/js/spec_helpers/ajax_helpers", "URI", "j var pagingContainer; beforeEach(function () { - pagingContainer = new MockPagingView({page_size: PAGE_SIZE}); + pagingContainer = new MockPagingView({ + page_size: PAGE_SIZE, + page: jasmine.createSpyObj('page', ['updatePreviewButton', 'renderAddXBlockComponents']) + }); }); describe("Container", function () { @@ -546,7 +549,7 @@ define(["jquery", "underscore", "common/js/spec_helpers/ajax_helpers", "URI", "j mockXBlockView.model.id = 'mock-location'; pagingContainer.refresh(mockXBlockView, true); expect(pagingContainer.render).toHaveBeenCalled(); - expect(pagingContainer.render.mostRecentCall.args[0].force_render).toEqual('mock-location'); + expect(pagingContainer.render.calls.mostRecent().args[0].force_render).toEqual('mock-location'); }); }); }); diff --git a/cms/static/js/spec/views/pages/container_spec.js b/cms/static/js/spec/views/pages/container_spec.js index fe78638..43d36f2 100644 --- a/cms/static/js/spec/views/pages/container_spec.js +++ b/cms/static/js/spec/views/pages/container_spec.js @@ -70,7 +70,7 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja containerPage.render(); respondWithHtml(html); AjaxHelpers.expectJsonRequest(requests, 'GET', '/xblock/locator-container'); - AjaxHelpers.respondWithJson(requests, options); + AjaxHelpers.respondWithJson(requests, options || {}); }; handleContainerPageRefresh = function(requests) { diff --git a/cms/static/js/spec/views/pages/container_subviews_spec.js b/cms/static/js/spec/views/pages/container_subviews_spec.js index 744b991..1d5385b 100644 --- a/cms/static/js/spec/views/pages/container_subviews_spec.js +++ b/cms/static/js/spec/views/pages/container_subviews_spec.js @@ -1,9 +1,10 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/ajax_helpers", "common/js/spec_helpers/template_helpers", "js/spec_helpers/edit_helpers", "common/js/components/views/feedback_prompt", "js/views/pages/container", - "js/views/pages/container_subviews", "js/models/xblock_info", "js/views/utils/xblock_utils"], + "js/views/pages/container_subviews", "js/models/xblock_info", "js/views/utils/xblock_utils", + 'js/models/course'], function ($, _, str, AjaxHelpers, TemplateHelpers, EditHelpers, Prompt, ContainerPage, ContainerSubviews, - XBlockInfo, XBlockUtils) { + XBlockInfo, XBlockUtils, Course) { var VisibilityState = XBlockUtils.VisibilityState; describe("Container Subviews", function() { @@ -14,12 +15,26 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja mockContainerXBlockHtml = readFixtures('mock/mock-empty-container-xblock.underscore'); beforeEach(function () { + window.course = new Course({ + id: '5', + name: 'Course Name', + url_name: 'course_name', + org: 'course_org', + num: 'course_num', + revision: 'course_rev' + }); + TemplateHelpers.installTemplate('xblock-string-field-editor'); TemplateHelpers.installTemplate('publish-xblock'); TemplateHelpers.installTemplate('publish-history'); TemplateHelpers.installTemplate('unit-outline'); TemplateHelpers.installTemplate('container-message'); appendSetFixtures(mockContainerPage); + requests = AjaxHelpers.requests(this); + }); + + afterEach(function() { + delete window.course; }); defaultXBlockInfo = { @@ -39,7 +54,6 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja }; createContainerPage = function (test, options) { - requests = AjaxHelpers.requests(test); model = new XBlockInfo(createXBlockInfo(options), { parse: true }); containerPage = new ContainerPage({ model: model, @@ -135,7 +149,7 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja // Confirm the discard. expect(promptSpies.constructor).toHaveBeenCalled(); - promptSpies.constructor.mostRecentCall.args[0].actions.primary.click(promptSpies); + promptSpies.constructor.calls.mostRecent().args[0].actions.primary.click(promptSpies); AjaxHelpers.expectJsonRequest(requests, "POST", "/xblock/locator-container", {"publish": "discard_changes"} @@ -152,8 +166,8 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja }; beforeEach(function() { - promptSpies = spyOnConstructor(Prompt, "Warning", ["show", "hide"]); - promptSpies.show.andReturn(this.promptSpies); + promptSpies = jasmine.stealth.spyOnConstructor(Prompt, "Warning", ["show", "hide"]); + promptSpies.show.and.returnValue(this.promptSpies); }); it('renders correctly with private content', function () { @@ -268,7 +282,7 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja var notificationSpy, renderPageSpy, numRequests; createContainerPage(this); notificationSpy = EditHelpers.createNotificationSpy(); - renderPageSpy = spyOn(containerPage.xblockPublisher, 'renderPage').andCallThrough(); + renderPageSpy = spyOn(containerPage.xblockPublisher, 'renderPage').and.callThrough(); sendDiscardChangesToServer(); numRequests = requests.length; @@ -287,7 +301,7 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja it('does not fetch if discard changes fails', function () { var renderPageSpy, numRequests; createContainerPage(this); - renderPageSpy = spyOn(containerPage.xblockPublisher, 'renderPage').andCallThrough(); + renderPageSpy = spyOn(containerPage.xblockPublisher, 'renderPage').and.callThrough(); sendDiscardChangesToServer(); @@ -309,7 +323,7 @@ define(["jquery", "underscore", "underscore.string", "common/js/spec_helpers/aja // Click cancel to confirmation. expect(promptSpies.constructor).toHaveBeenCalled(); - promptSpies.constructor.mostRecentCall.args[0].actions.secondary.click(promptSpies); + promptSpies.constructor.calls.mostRecent().args[0].actions.secondary.click(promptSpies); AjaxHelpers.expectNoRequests(requests); expect(containerPage.$(discardChangesButtonCss)).not.toHaveClass('is-disabled'); }); diff --git a/cms/static/js/spec/views/pages/course_outline_spec.js b/cms/static/js/spec/views/pages/course_outline_spec.js index 2db0878..e8db1e1 100644 --- a/cms/static/js/spec/views/pages/course_outline_spec.js +++ b/cms/static/js/spec/views/pages/course_outline_spec.js @@ -1,14 +1,15 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/utils/view_utils", "js/views/pages/course_outline", "js/models/xblock_outline_info", "js/utils/date_utils", "js/spec_helpers/edit_helpers", - "common/js/spec_helpers/template_helpers"], - function($, AjaxHelpers, ViewUtils, CourseOutlinePage, XBlockOutlineInfo, DateUtils, EditHelpers, TemplateHelpers) { + "common/js/spec_helpers/template_helpers", 'js/models/course',], + function($, AjaxHelpers, ViewUtils, CourseOutlinePage, XBlockOutlineInfo, DateUtils, + EditHelpers, TemplateHelpers, Course) { describe("CourseOutlinePage", function() { var createCourseOutlinePage, displayNameInput, model, outlinePage, requests, getItemsOfType, getItemHeaders, verifyItemsExpanded, expandItemsAndVerifyState, collapseItemsAndVerifyState, createMockCourseJSON, createMockSectionJSON, createMockSubsectionJSON, verifyTypePublishable, mockCourseJSON, mockEmptyCourseJSON, mockSingleSectionCourseJSON, - createMockVerticalJSON, createMockIndexJSON, mockCourseEntranceExamJSON + createMockVerticalJSON, createMockIndexJSON, mockCourseEntranceExamJSON, mockOutlinePage = readFixtures('mock/mock-course-outline-page.underscore'), mockRerunNotification = readFixtures('mock/mock-course-rerun-notification.underscore'); @@ -214,6 +215,15 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u }; beforeEach(function () { + window.course = new Course({ + id: '5', + name: 'Course Name', + url_name: 'course_name', + org: 'course_org', + num: 'course_num', + revision: 'course_rev' + }); + EditHelpers.installMockAnalytics(); EditHelpers.installViewTemplates(); TemplateHelpers.installTemplates([ @@ -252,6 +262,7 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u $("#start_date").datepicker( "destroy" ); $("#due_date").datepicker( "destroy" ); $('.ui-datepicker').remove(); + delete window.course; }); describe('Initial display', function() { @@ -346,8 +357,8 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u it('can start reindex of a course', function() { createCourseOutlinePage(this, mockSingleSectionCourseJSON); - var reindexSpy = spyOn(outlinePage, 'startReIndex').andCallThrough(); - var successSpy = spyOn(outlinePage, 'onIndexSuccess').andCallThrough(); + var reindexSpy = spyOn(outlinePage, 'startReIndex').and.callThrough(); + var successSpy = spyOn(outlinePage, 'onIndexSuccess').and.callThrough(); var reindexButton = outlinePage.$('.button.button-reindex'); var test_url = '/course/5/search_reindex'; reindexButton.attr('href', test_url) @@ -360,11 +371,11 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/components/u it('shows an error message when reindexing fails', function() { createCourseOutlinePage(this, mockSingleSectionCourseJSON); - var reindexSpy = spyOn(outlinePage, 'startReIndex').andCallThrough(); - var errorSpy = spyOn(outlinePage, 'onIndexError').andCallThrough(); + var reindexSpy = spyOn(outlinePage, 'startReIndex').and.callThrough(); + var errorSpy = spyOn(outlinePage, 'onIndexError').and.callThrough(); var reindexButton = outlinePage.$('.button.button-reindex'); var test_url = '/course/5/search_reindex'; - reindexButton.attr('href', test_url) + reindexButton.attr('href', test_url); reindexButton.trigger('click'); AjaxHelpers.expectJsonRequest(requests, 'GET', test_url); AjaxHelpers.respondWithError(requests, 500, createMockIndexJSON(false)); diff --git a/cms/static/js/spec/views/pages/group_configurations_spec.js b/cms/static/js/spec/views/pages/group_configurations_spec.js index 52c5316..03e8397 100644 --- a/cms/static/js/spec/views/pages/group_configurations_spec.js +++ b/cms/static/js/spec/views/pages/group_configurations_spec.js @@ -40,9 +40,15 @@ define([ 'content-group-editor', 'group-edit', 'list' ]); - this.addMatchers({ + jasmine.addMatchers({ toBeExpanded: function () { - return Boolean($('a.group-toggle.hide-groups', $(this.actual)).length); + return { + compare: function (actual) { + return { + pass: Boolean($('a.group-toggle.hide-groups', $(actual)).length) + }; + } + }; } }); }); @@ -67,7 +73,7 @@ define([ }); it('should focus and expand if its id is part of url hash', function() { - spyOn(this.view, 'getLocationHash').andReturn('#0'); + spyOn(this.view, 'getLocationHash').and.returnValue('#0'); this.view.render(); // We cannot use .toBeFocused due to flakiness. expect($.fn.focus).toHaveBeenCalled(); @@ -75,14 +81,14 @@ define([ }); it('should not focus on any experiment configuration if url hash is empty', function() { - spyOn(this.view, 'getLocationHash').andReturn(''); + spyOn(this.view, 'getLocationHash').and.returnValue(''); this.view.render(); expect($.fn.focus).not.toHaveBeenCalled(); expect(this.view.$(groupConfigItemClassName)).not.toBeExpanded(); }); it('should not focus on any experiment configuration if url hash contains wrong id', function() { - spyOn(this.view, 'getLocationHash').andReturn('#1'); + spyOn(this.view, 'getLocationHash').and.returnValue('#1'); this.view.render(); expect($.fn.focus).not.toHaveBeenCalled(); expect(this.view.$(groupConfigItemClassName)).not.toBeExpanded(); diff --git a/cms/static/js/spec/views/pages/library_users_spec.js b/cms/static/js/spec/views/pages/library_users_spec.js index 3a747d9..1c77948 100644 --- a/cms/static/js/spec/views/pages/library_users_spec.js +++ b/cms/static/js/spec/views/pages/library_users_spec.js @@ -22,7 +22,7 @@ function ($, AjaxHelpers, ViewHelpers, ManageUsersFactory, ViewUtils) { describe("read-write access", function() { var mockHTML = readFixtures('mock/mock-manage-users-lib.underscore'); - beforeEach(function () { + beforeEach(function (done) { ViewHelpers.installMockAnalytics(); setFixtures(mockHTML); appendSetFixtures($("<script>", { id: "team-member-tpl", type: "text/template"}).text(team_member_fixture)); @@ -37,9 +37,10 @@ function ($, AjaxHelpers, ViewHelpers, ManageUsersFactory, ViewUtils) { 10000, true ); - waitsFor(function(){ - return $(".ui-loading").length === 0; - }, "Waiting for backbone render to happen", 1000); + + jasmine.waitUntil(function() { + return ($(".ui-loading").length === 0); + }).then(done); }); afterEach(function () { diff --git a/cms/static/js/spec/views/previous_video_upload_spec.js b/cms/static/js/spec/views/previous_video_upload_spec.js index 0244b7f..63e965a 100644 --- a/cms/static/js/spec/views/previous_video_upload_spec.js +++ b/cms/static/js/spec/views/previous_video_upload_spec.js @@ -47,7 +47,7 @@ define( it("should render created timestamp correctly", function() { var fakeDate = "fake formatted date"; - spyOn(Date.prototype, "toLocaleString").andCallFake( + spyOn(Date.prototype, "toLocaleString").and.callFake( function(locales, options) { expect(locales).toEqual([]); expect(options.timeZone).toEqual("UTC"); diff --git a/cms/static/js/spec/views/unit_outline_spec.js b/cms/static/js/spec/views/unit_outline_spec.js index c033018..2f5b5ef 100644 --- a/cms/static/js/spec/views/unit_outline_spec.js +++ b/cms/static/js/spec/views/unit_outline_spec.js @@ -1,6 +1,8 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/spec_helpers/template_helpers", - "common/js/spec_helpers/view_helpers", "common/js/components/utils/view_utils", "js/views/unit_outline", "js/models/xblock_info"], - function ($, AjaxHelpers, TemplateHelpers, ViewHelpers, ViewUtils, UnitOutlineView, XBlockInfo) { + "common/js/spec_helpers/view_helpers", "common/js/components/utils/view_utils", "js/models/course", + "js/views/unit_outline", "js/models/xblock_info"], + function ($, AjaxHelpers, TemplateHelpers, ViewHelpers, ViewUtils, + Course, UnitOutlineView, XBlockInfo) { describe("UnitOutlineView", function() { var createUnitOutlineView, createMockXBlockInfo, @@ -71,6 +73,14 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/spec_helpers }; beforeEach(function () { + window.course = new Course({ + id: '5', + name: 'Course Name', + url_name: 'course_name', + org: 'course_org', + num: 'course_num', + revision: 'course_rev' + }); ViewHelpers.installMockAnalytics(); ViewHelpers.installViewTemplates(); TemplateHelpers.installTemplate('unit-outline'); @@ -78,6 +88,7 @@ define(["jquery", "common/js/spec_helpers/ajax_helpers", "common/js/spec_helpers }); afterEach(function () { + delete window.course; ViewHelpers.removeMockAnalytics(); }); diff --git a/cms/static/js/spec/views/xblock_spec.js b/cms/static/js/spec/views/xblock_spec.js index 755d790..bcbfabf 100644 --- a/cms/static/js/spec/views/xblock_spec.js +++ b/cms/static/js/spec/views/xblock_spec.js @@ -91,7 +91,7 @@ define(["jquery", "URI", "common/js/spec_helpers/ajax_helpers", "common/js/compo var requests = AjaxHelpers.requests(this), missingJavaScriptUrl = "no_such_file.js", promise; - spyOn(ViewUtils, 'loadJavaScript').andReturn($.Deferred().reject().promise()); + spyOn(ViewUtils, 'loadJavaScript').and.returnValue($.Deferred().reject().promise()); promise = postXBlockRequest(requests, [ ["hash5", { mimetype: "application/javascript", kind: "url", data: missingJavaScriptUrl }] ]); @@ -99,7 +99,7 @@ define(["jquery", "URI", "common/js/spec_helpers/ajax_helpers", "common/js/compo }); it('Triggers an event to the runtime when a notification-action-button is clicked', function () { - var notifySpy = spyOn(xblockView, "notifyRuntime").andCallThrough(); + var notifySpy = spyOn(xblockView, "notifyRuntime").and.callThrough(); postXBlockRequest(AjaxHelpers.requests(this), []); xblockView.$el.find(".notification-action-button").click(); diff --git a/cms/static/js/views/experiment_group_edit.js b/cms/static/js/views/experiment_group_edit.js index 2a5f55e..c513b1a 100644 --- a/cms/static/js/views/experiment_group_edit.js +++ b/cms/static/js/views/experiment_group_edit.js @@ -3,9 +3,9 @@ * It is expected to be backed by a Group model. */ define([ - 'js/views/baseview' + 'js/views/baseview', 'underscore', 'underscore.string', 'gettext', 'text!templates/group-edit.underscore' ], -function(BaseView) { +function(BaseView, _, str, gettext, groupEditTemplate) { 'use strict'; var ExperimentGroupEditView = BaseView.extend({ tagName: 'li', @@ -22,7 +22,6 @@ function(BaseView) { }, initialize: function() { - this.template = this.loadTemplate('group-edit'); this.listenTo(this.model, 'change', this.render); }, @@ -30,7 +29,7 @@ function(BaseView) { var collection = this.model.collection, index = collection.indexOf(this.model); - this.$el.html(this.template({ + this.$el.html(_.template(groupEditTemplate)({ name: this.model.get('name'), allocation: this.getAllocation(), index: index, diff --git a/cms/static/js/views/license.js b/cms/static/js/views/license.js index 3e8f9a1..f5a17d9 100644 --- a/cms/static/js/views/license.js +++ b/cms/static/js/views/license.js @@ -1,4 +1,8 @@ -define(["js/views/baseview", "underscore"], function(BaseView, _) { +define([ + "js/views/baseview", + "underscore", + "text!templates/license-selector.underscore" +], function(BaseView, _, licenseSelectorTemplate) { var defaultLicenseInfo = { "all-rights-reserved": { "name": gettext("All Rights Reserved"), @@ -55,7 +59,6 @@ define(["js/views/baseview", "underscore"], function(BaseView, _) { initialize: function(options) { this.licenseInfo = options.licenseInfo || defaultLicenseInfo; this.showPreview = !!options.showPreview; // coerce to boolean - this.template = this.loadTemplate("license-selector"); // Rerender when the model changes this.listenTo(this.model, 'change', this.render); @@ -79,7 +82,7 @@ define(["js/views/baseview", "underscore"], function(BaseView, _) { }, render: function() { - this.$el.html(this.template({ + this.$el.html(_.template(licenseSelectorTemplate)({ model: this.model.attributes, licenseString: this.model.toString() || "", licenseInfo: this.licenseInfo, diff --git a/cms/static/js_test.yml b/cms/static/js_test.yml index 92a8dcf..22a4e56 100644 --- a/cms/static/js_test.yml +++ b/cms/static/js_test.yml @@ -48,10 +48,9 @@ lib_paths: - xmodule_js/common_static/js/vendor/html5-input-polyfills/number-polyfill.js - xmodule_js/common_static/js/vendor/sinon-1.17.0.js - xmodule_js/common_static/js/vendor/Squire.js - - xmodule_js/common_static/js/vendor/jasmine-jquery.js - - xmodule_js/common_static/js/vendor/jasmine-stealth.js + - xmodule_js/common_static/js/libs/jasmine-stealth.js + - xmodule_js/common_static/js/libs/jasmine-waituntil.js - xmodule_js/common_static/js/vendor/jasmine-imagediff.js - - xmodule_js/common_static/js/vendor/jasmine.async.js - xmodule_js/common_static/js/vendor/CodeMirror/codemirror.js - xmodule_js/common_static/js/vendor/jQuery-File-Upload/js - xmodule_js/src/xmodule.js diff --git a/cms/static/js_test_squire.yml b/cms/static/js_test_squire.yml index 1122188..d65f44e 100644 --- a/cms/static/js_test_squire.yml +++ b/cms/static/js_test_squire.yml @@ -45,10 +45,7 @@ lib_paths: - xmodule_js/common_static/js/vendor/html5-input-polyfills/number-polyfill.js - xmodule_js/common_static/js/vendor/sinon-1.17.0.js - xmodule_js/common_static/js/vendor/Squire.js - - xmodule_js/common_static/js/vendor/jasmine-jquery.js - - xmodule_js/common_static/js/vendor/jasmine-stealth.js - xmodule_js/common_static/js/vendor/jasmine-imagediff.js - - xmodule_js/common_static/js/vendor/jasmine.async.js - xmodule_js/common_static/js/vendor/CodeMirror/codemirror.js - xmodule_js/common_static/js/vendor/domReady.js - xmodule_js/common_static/js/vendor/URI.min.js diff --git a/cms/static/karma_cms.conf.js b/cms/static/karma_cms.conf.js index 871eed5..5c5d2fe 100644 --- a/cms/static/karma_cms.conf.js +++ b/cms/static/karma_cms.conf.js @@ -78,6 +78,7 @@ var files = [ {pattern: 'xmodule_js/common_static/js/vendor/requirejs/text.js', included: false}, // Paths to source JavaScript files + {pattern: 'xmodule_js/common_static/js/libs/jasmine-extensions.js', included: true, nocache: true}, {pattern: 'coffee/src/**/*.js', included: false, nocache: true}, {pattern: 'js/**/*.js', included: false, nocache: true}, {pattern: 'js/certificates/**/*.js', included: false, nocache: true}, diff --git a/cms/static/karma_cms_squire.conf.js b/cms/static/karma_cms_squire.conf.js index bd89960..501133a 100644 --- a/cms/static/karma_cms_squire.conf.js +++ b/cms/static/karma_cms_squire.conf.js @@ -70,6 +70,7 @@ var files = [ {pattern: 'xmodule_js/common_static/js/vendor/requirejs/text.js', included: false}, // Paths to source JavaScript files + {pattern: 'xmodule_js/common_static/js/libs/jasmine-extensions.js', included: true, nocache: true}, {pattern: 'coffee/src/**/*.js', included: false, nocache: true}, {pattern: 'js/collections/**/*.js', included: false, nocache: true}, {pattern: 'js/models/**/*.js', included: false, nocache: true}, diff --git a/cms/templates/js/mock/mock-xmodule-editor-with-custom-tabs.underscore b/cms/templates/js/mock/mock-xmodule-editor-with-custom-tabs.underscore index b37459e..c27d8f0 100644 --- a/cms/templates/js/mock/mock-xmodule-editor-with-custom-tabs.underscore +++ b/cms/templates/js/mock/mock-xmodule-editor-with-custom-tabs.underscore @@ -1,6 +1,6 @@ <div class="xblock xblock-studio_view xmodule_edit xmodule_WrapperDescriptor" data-runtime-class="StudioRuntime" data-init="XBlockToXModuleShim" data-runtime-version="1" data-usage-id="i4x:;_;_edX;_mock" - data-type="VerticalDescriptor" tabindex="0"> + data-type="MockDescriptor" tabindex="0"> <div class="wrapper-comp-editor is-active" id="editor-tab" data-base-asset-url="/c4x/AndyA/ABT101/asset/"> <section class="editor-with-tabs"> <div class="edit-header"> diff --git a/cms/templates/js/mock/mock-xmodule-settings-only-editor.underscore b/cms/templates/js/mock/mock-xmodule-settings-only-editor.underscore index 325cc06..5013204 100644 --- a/cms/templates/js/mock/mock-xmodule-settings-only-editor.underscore +++ b/cms/templates/js/mock/mock-xmodule-settings-only-editor.underscore @@ -1,4 +1,4 @@ -<div class="xblock xblock-studio_view xmodule_edit xmodule_WrapperDescriptor" data-runtime-class="StudioRuntime" data-init="XBlockToXModuleShim" data-runtime-version="1" data-usage-id="i4x:;_;_AndyA;_ABT101;_wrapper;_wrapper_l1_poll" data-type="VerticalDescriptor" tabindex="0"> +<div class="xblock xblock-studio_view xmodule_edit xmodule_WrapperDescriptor" data-runtime-class="StudioRuntime" data-init="XBlockToXModuleShim" data-runtime-version="1" data-usage-id="i4x:;_;_AndyA;_ABT101;_wrapper;_wrapper_l1_poll" data-type="MockDescriptor" tabindex="0"> <section class="sequence-edit"> <script id="metadata-editor-tpl" type="text/template"> <ul class="list-input settings-list"> diff --git a/common/static/js/libs/jasmine-extensions.js b/common/static/js/libs/jasmine-extensions.js index 47b9561..155504d 100644 --- a/common/static/js/libs/jasmine-extensions.js +++ b/common/static/js/libs/jasmine-extensions.js @@ -10,7 +10,13 @@ (function(root, factory) { /* jshint strict: false */ - factory(root, root.jQuery); + if (typeof define === 'function' && define.amd) { + require(['jquery'], function ($) { + factory(root, $); + }); + } else { + factory(root, root.jQuery); + } }((function() { /* jshint strict: false */ return this; @@ -20,7 +26,9 @@ // Add custom Jasmine matchers. beforeEach(function() { - jasmine.addMatchers(window.imagediff.jasmine); + if (window.imagediff) { + jasmine.addMatchers(window.imagediff.jasmine); + } jasmine.addMatchers({ toHaveAttrs: function() { @@ -60,6 +68,16 @@ }; } }; + }, + toBeInstanceOf: function() { + // Assert the type of the value being tested matches the provided type + return { + compare: function (actual, expected) { + return { + pass: actual instanceof expected + }; + } + }; } }); }); diff --git a/pavelib/utils/envs.py b/pavelib/utils/envs.py index b458499..a1d16e9 100644 --- a/pavelib/utils/envs.py +++ b/pavelib/utils/envs.py @@ -122,8 +122,8 @@ class Env(object): 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_squire.conf.js', + REPO_ROOT / 'cms/static/karma_cms.conf.js', + REPO_ROOT / 'cms/static/karma_cms_squire.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_requirejs.conf.js', @@ -132,8 +132,8 @@ class Env(object): JS_TEST_ID_KEYS = [ # 'lms', # 'lms-coffee', - # 'cms', - # 'cms-squire', + 'cms', + 'cms-squire', 'xmodule', 'common', 'common-requirejs'