319 lines
15 KiB
CoffeeScript
319 lines
15 KiB
CoffeeScript
define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js/models/section",
|
|
"js/collections/textbook", "js/views/show_textbook", "js/views/edit_textbook", "js/views/list_textbooks",
|
|
"js/views/edit_chapter", "js/views/feedback_prompt", "js/views/feedback_notification",
|
|
"sinon", "jasmine-stealth"],
|
|
(Textbook, Chapter, ChapterSet, Section, TextbookSet, ShowTextbook, EditTextbook, ListTexbook, EditChapter, Prompt, Notification, sinon) ->
|
|
feedbackTpl = readFixtures('system-feedback.underscore')
|
|
|
|
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')
|
|
|
|
beforeEach ->
|
|
setFixtures($("<script>", {id: "show-textbook-tpl", type: "text/template"}).text(tpl))
|
|
appendSetFixtures($("<script>", {id: "system-feedback-tpl", type: "text/template"}).text(feedbackTpl))
|
|
appendSetFixtures(sandbox({id: "page-notification"}))
|
|
appendSetFixtures(sandbox({id: "page-prompt"}))
|
|
@model = new Textbook({name: "Life Sciences", id: "0life-sciences"})
|
|
spyOn(@model, "destroy").andCallThrough()
|
|
@collection = new TextbookSet([@model])
|
|
@view = new ShowTextbook({model: @model})
|
|
|
|
@promptSpies = spyOnConstructor(Prompt, "Warning", ["show", "hide"])
|
|
@promptSpies.show.andReturn(@promptSpies)
|
|
window.section = new Section({
|
|
id: "5",
|
|
name: "Course Name",
|
|
url_name: "course_name",
|
|
org: "course_org",
|
|
num: "course_num",
|
|
revision: "course_rev"
|
|
});
|
|
|
|
afterEach ->
|
|
delete window.section
|
|
|
|
describe "Basic", ->
|
|
it "should render properly", ->
|
|
@view.render()
|
|
expect(@view.$el).toContainText("Life Sciences")
|
|
|
|
it "should set the 'editing' property on the model when the edit button is clicked", ->
|
|
@view.render().$(".edit").click()
|
|
expect(@model.get("editing")).toBeTruthy()
|
|
|
|
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]
|
|
expect(ctorOptions.title).toMatch(/Life Sciences/)
|
|
# hasn't actually been removed
|
|
expect(@model.destroy).not.toHaveBeenCalled()
|
|
expect(@collection).toContain(@model)
|
|
|
|
it "should show chapters appropriately", ->
|
|
@model.get("chapters").add([{}, {}, {}])
|
|
@model.set('showChapters', false)
|
|
@view.render().$(".show-chapters").click()
|
|
expect(@model.get('showChapters')).toBeTruthy()
|
|
|
|
it "should hide chapters appropriately", ->
|
|
@model.get("chapters").add([{}, {}, {}])
|
|
@model.set('showChapters', true)
|
|
@view.render().$(".hide-chapters").click()
|
|
expect(@model.get('showChapters')).toBeFalsy()
|
|
|
|
describe "AJAX", ->
|
|
beforeEach ->
|
|
@requests = requests = []
|
|
@xhr = sinon.useFakeXMLHttpRequest()
|
|
@xhr.onCreate = (xhr) -> requests.push(xhr)
|
|
|
|
@savingSpies = spyOnConstructor(Notification, "Mini",
|
|
["show", "hide"])
|
|
@savingSpies.show.andReturn(@savingSpies)
|
|
|
|
afterEach ->
|
|
@xhr.restore()
|
|
|
|
it "should destroy itself on confirmation", ->
|
|
@view.render().$(".delete").click()
|
|
ctorOptions = @promptSpies.constructor.mostRecentCall.args[0]
|
|
# run the primary function to indicate confirmation
|
|
ctorOptions.actions.primary.click(@promptSpies)
|
|
# AJAX request has been sent, but not yet returned
|
|
expect(@model.destroy).toHaveBeenCalled()
|
|
expect(@requests.length).toEqual(1)
|
|
expect(@savingSpies.constructor).toHaveBeenCalled()
|
|
expect(@savingSpies.show).toHaveBeenCalled()
|
|
expect(@savingSpies.hide).not.toHaveBeenCalled()
|
|
savingOptions = @savingSpies.constructor.mostRecentCall.args[0]
|
|
expect(savingOptions.title).toMatch(/Deleting/)
|
|
# return a success response
|
|
@requests[0].respond(200)
|
|
expect(@savingSpies.hide).toHaveBeenCalled()
|
|
expect(@collection.contains(@model)).toBeFalsy()
|
|
|
|
describe "EditTextbook", ->
|
|
describe "Basic", ->
|
|
tpl = readFixtures('edit-textbook.underscore')
|
|
chapterTpl = readFixtures('edit-chapter.underscore')
|
|
|
|
beforeEach ->
|
|
setFixtures($("<script>", {id: "edit-textbook-tpl", type: "text/template"}).text(tpl))
|
|
appendSetFixtures($("<script>", {id: "edit-chapter-tpl", type: "text/template"}).text(chapterTpl))
|
|
appendSetFixtures($("<script>", {id: "system-feedback-tpl", type: "text/template"}).text(feedbackTpl))
|
|
appendSetFixtures(sandbox({id: "page-notification"}))
|
|
appendSetFixtures(sandbox({id: "page-prompt"}))
|
|
@model = new Textbook({name: "Life Sciences", editing: true})
|
|
spyOn(@model, 'save')
|
|
@collection = new TextbookSet()
|
|
@collection.add(@model)
|
|
@view = new EditTextbook({model: @model})
|
|
spyOn(@view, 'render').andCallThrough()
|
|
|
|
it "should render properly", ->
|
|
@view.render()
|
|
expect(@view.$("input[name=textbook-name]").val()).toEqual("Life Sciences")
|
|
|
|
it "should allow you to create new empty chapters", ->
|
|
@view.render()
|
|
numChapters = @model.get("chapters").length
|
|
@view.$(".action-add-chapter").click()
|
|
expect(@model.get("chapters").length).toEqual(numChapters+1)
|
|
expect(@model.get("chapters").last().isEmpty()).toBeTruthy()
|
|
|
|
it "should save properly", ->
|
|
@view.render()
|
|
@view.$("input[name=textbook-name]").val("starfish")
|
|
@view.$("input[name=chapter1-name]").val("wallflower")
|
|
@view.$("input[name=chapter1-asset-path]").val("foobar")
|
|
@view.$("form").submit()
|
|
expect(@model.get("name")).toEqual("starfish")
|
|
chapter = @model.get("chapters").first()
|
|
expect(chapter.get("name")).toEqual("wallflower")
|
|
expect(chapter.get("asset_path")).toEqual("foobar")
|
|
expect(@model.save).toHaveBeenCalled()
|
|
|
|
it "should not save on invalid", ->
|
|
@view.render()
|
|
@view.$("input[name=textbook-name]").val("")
|
|
@view.$("input[name=chapter1-asset-path]").val("foobar.pdf")
|
|
@view.$("form").submit()
|
|
expect(@model.validationError).toBeTruthy()
|
|
expect(@model.save).not.toHaveBeenCalled()
|
|
|
|
it "does not save on cancel", ->
|
|
@model.get("chapters").add([{name: "a", asset_path: "b"}])
|
|
@view.render()
|
|
@view.$("input[name=textbook-name]").val("starfish")
|
|
@view.$("input[name=chapter1-asset-path]").val("foobar.pdf")
|
|
@view.$(".action-cancel").click()
|
|
expect(@model.get("name")).not.toEqual("starfish")
|
|
chapter = @model.get("chapters").first()
|
|
expect(chapter.get("asset_path")).not.toEqual("foobar")
|
|
expect(@model.save).not.toHaveBeenCalled()
|
|
|
|
it "should be possible to correct validation errors", ->
|
|
@view.render()
|
|
@view.$("input[name=textbook-name]").val("")
|
|
@view.$("input[name=chapter1-asset-path]").val("foobar.pdf")
|
|
@view.$("form").submit()
|
|
expect(@model.validationError).toBeTruthy()
|
|
expect(@model.save).not.toHaveBeenCalled()
|
|
@view.$("input[name=textbook-name]").val("starfish")
|
|
@view.$("input[name=chapter1-name]").val("foobar")
|
|
@view.$("form").submit()
|
|
expect(@model.validationError).toBeFalsy()
|
|
expect(@model.save).toHaveBeenCalled()
|
|
|
|
it "removes all empty chapters on cancel if the model has a non-empty chapter", ->
|
|
chapters = @model.get("chapters")
|
|
chapters.at(0).set("name", "non-empty")
|
|
@model.setOriginalAttributes()
|
|
@view.render()
|
|
chapters.add([{}, {}, {}]) # add three empty chapters
|
|
expect(chapters.length).toEqual(4)
|
|
@view.$(".action-cancel").click()
|
|
expect(chapters.length).toEqual(1)
|
|
expect(chapters.first().get('name')).toEqual("non-empty")
|
|
|
|
it "removes all empty chapters on cancel except one if the model has no non-empty chapters", ->
|
|
chapters = @model.get("chapters")
|
|
@view.render()
|
|
chapters.add([{}, {}, {}]) # add three empty chapters
|
|
expect(chapters.length).toEqual(4)
|
|
@view.$(".action-cancel").click()
|
|
expect(chapters.length).toEqual(1)
|
|
|
|
|
|
# describe "ListTextbooks", ->
|
|
# noTextbooksTpl = readFixtures("no-textbooks.underscore")
|
|
#
|
|
# beforeEach ->
|
|
# setFixtures($("<script>", {id: "no-textbooks-tpl", type: "text/template"}).text(noTextbooksTpl))
|
|
# appendSetFixtures($("<script>", {id: "system-feedback-tpl", type: "text/template"}).text(feedbackTpl))
|
|
# @showSpies = spyOnConstructor("ShowTextbook", ["render"])
|
|
# @showSpies.render.andReturn(@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.$el = editEl
|
|
# @editSpies.el= editEl.get(0)
|
|
#
|
|
# @collection = new TextbookSet
|
|
# @view = new ListTextbooks({collection: @collection})
|
|
# @view.render()
|
|
#
|
|
# it "should render the empty template if there are no textbooks", ->
|
|
# expect(@view.$el).toContainText("You haven't added any textbooks to this course yet")
|
|
# expect(@view.$el).toContain(".new-button")
|
|
# expect(@showSpies.constructor).not.toHaveBeenCalled()
|
|
# expect(@editSpies.constructor).not.toHaveBeenCalled()
|
|
#
|
|
# it "should render ShowTextbook views by default if no textbook is being edited", ->
|
|
# # add three empty textbooks to the collection
|
|
# @collection.add([{}, {}, {}])
|
|
# # reset spies due to re-rendering on collection modification
|
|
# @showSpies.constructor.reset()
|
|
# @editSpies.constructor.reset()
|
|
# # render once and test
|
|
# @view.render()
|
|
#
|
|
# expect(@view.$el).not.toContainText(
|
|
# "You haven't added any textbooks to this course yet")
|
|
# expect(@showSpies.constructor).toHaveBeenCalled()
|
|
# expect(@showSpies.constructor.calls.length).toEqual(3);
|
|
# expect(@editSpies.constructor).not.toHaveBeenCalled()
|
|
#
|
|
# it "should render an EditTextbook view for a textbook being edited", ->
|
|
# # add three empty textbooks to the collection: the first and third
|
|
# # should be shown, and the second should be edited
|
|
# @collection.add([{editing: false}, {editing: true}, {editing: false}])
|
|
# editing = @collection.at(1)
|
|
# expect(editing.get("editing")).toBeTruthy()
|
|
# # reset spies
|
|
# @showSpies.constructor.reset()
|
|
# @editSpies.constructor.reset()
|
|
# # render once and test
|
|
# @view.render()
|
|
#
|
|
# expect(@showSpies.constructor).toHaveBeenCalled()
|
|
# expect(@showSpies.constructor.calls.length).toEqual(2)
|
|
# expect(@showSpies.constructor).not.toHaveBeenCalledWith({model: editing})
|
|
# expect(@editSpies.constructor).toHaveBeenCalled()
|
|
# expect(@editSpies.constructor.calls.length).toEqual(1)
|
|
# expect(@editSpies.constructor).toHaveBeenCalledWith({model: editing})
|
|
#
|
|
# it "should add a new textbook when the new-button is clicked", ->
|
|
# # reset spies
|
|
# @showSpies.constructor.reset()
|
|
# @editSpies.constructor.reset()
|
|
# # test
|
|
# @view.$(".new-button").click()
|
|
#
|
|
# expect(@collection.length).toEqual(1)
|
|
# expect(@view.$el).toContain(@editSpies.$el)
|
|
# expect(@view.$el).not.toContain(@showSpies.$el)
|
|
|
|
|
|
describe "EditChapter", ->
|
|
tpl = readFixtures("edit-chapter.underscore")
|
|
|
|
beforeEach ->
|
|
setFixtures($("<script>", {id: "edit-chapter-tpl", type: "text/template"}).text(tpl))
|
|
appendSetFixtures($("<script>", {id: "system-feedback-tpl", type: "text/template"}).text(feedbackTpl))
|
|
@model = new Chapter
|
|
name: "Chapter 1"
|
|
asset_path: "/ch1.pdf"
|
|
@collection = new ChapterSet()
|
|
@collection.add(@model)
|
|
@view = new EditChapter({model: @model})
|
|
spyOn(@view, "remove").andCallThrough()
|
|
CMS.URL.UPLOAD_ASSET = "/upload"
|
|
window.section = new Section({name: "abcde"})
|
|
|
|
afterEach ->
|
|
delete CMS.URL.UPLOAD_ASSET
|
|
delete window.section
|
|
|
|
it "can render", ->
|
|
@view.render()
|
|
expect(@view.$("input.chapter-name").val()).toEqual("Chapter 1")
|
|
expect(@view.$("input.chapter-asset-path").val()).toEqual("/ch1.pdf")
|
|
|
|
it "can delete itself", ->
|
|
@view.render().$(".action-close").click()
|
|
expect(@collection.length).toEqual(0)
|
|
expect(@view.remove).toHaveBeenCalled()
|
|
|
|
# it "can open an upload dialog", ->
|
|
# uploadSpies = spyOnConstructor("UploadDialog", ["show", "el"])
|
|
# uploadSpies.show.andReturn(uploadSpies)
|
|
#
|
|
# @view.render().$(".action-upload").click()
|
|
# ctorOptions = uploadSpies.constructor.mostRecentCall.args[0]
|
|
# expect(ctorOptions.model.get('title')).toMatch(/abcde/)
|
|
# expect(typeof ctorOptions.onSuccess).toBe('function')
|
|
# expect(uploadSpies.show).toHaveBeenCalled()
|
|
|
|
it "saves content when opening upload dialog", ->
|
|
@view.render()
|
|
@view.$("input.chapter-name").val("rainbows")
|
|
@view.$("input.chapter-asset-path").val("unicorns")
|
|
@view.$(".action-upload").click()
|
|
expect(@model.get("name")).toEqual("rainbows")
|
|
expect(@model.get("asset_path")).toEqual("unicorns")
|