This basically commits the transpiled CoffeeScript JS (with minor cleanup) and removes coffee build support. A tiny amount of support for xblocks exists, because external users may have xblocks with coffee. But no coffee in our tree anyway.
429 lines
20 KiB
JavaScript
429 lines
20 KiB
JavaScript
define(["jquery", "edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers", "squire"],
|
|
function($, AjaxHelpers, Squire) {
|
|
|
|
const assetLibraryTpl = readFixtures('asset-library.underscore');
|
|
const assetTpl = readFixtures('asset.underscore');
|
|
|
|
describe("Asset view", function() {
|
|
beforeEach(function(done) {
|
|
setFixtures($("<script>", {id: "asset-tpl", type: "text/template"}).text(assetTpl));
|
|
appendSetFixtures(sandbox({id: "page-prompt"}));
|
|
|
|
this.promptSpies = jasmine.createSpyObj('Prompt.Warning', ["constructor", "show", "hide"]);
|
|
this.promptSpies.constructor.and.returnValue(this.promptSpies);
|
|
this.promptSpies.show.and.returnValue(this.promptSpies);
|
|
|
|
this.confirmationSpies = jasmine.createSpyObj('Notification.Confirmation', ["constructor", "show"]);
|
|
this.confirmationSpies.constructor.and.returnValue(this.confirmationSpies);
|
|
this.confirmationSpies.show.and.returnValue(this.confirmationSpies);
|
|
|
|
this.savingSpies = jasmine.createSpyObj('Notification.Mini', ["constructor", "show", "hide"]);
|
|
this.savingSpies.constructor.and.returnValue(this.savingSpies);
|
|
this.savingSpies.show.and.returnValue(this.savingSpies);
|
|
|
|
this.injector = new Squire();
|
|
this.injector.mock("common/js/components/views/feedback_prompt", {
|
|
"Warning": this.promptSpies.constructor
|
|
});
|
|
this.injector.mock("common/js/components/views/feedback_notification", {
|
|
"Confirmation": this.confirmationSpies.constructor,
|
|
"Mini": this.savingSpies.constructor
|
|
});
|
|
|
|
this.injector.require(["js/models/asset", "js/collections/asset", "js/views/asset"],
|
|
(AssetModel, AssetCollection, AssetView) => {
|
|
this.model = new AssetModel({
|
|
display_name: "test asset",
|
|
url: 'actual_asset_url',
|
|
portable_url: 'portable_url',
|
|
date_added: 'date',
|
|
thumbnail: null,
|
|
id: 'id'
|
|
});
|
|
spyOn(this.model, "destroy").and.callThrough();
|
|
spyOn(this.model, "save").and.callThrough();
|
|
|
|
this.collection = new AssetCollection([this.model]);
|
|
this.collection.url = "assets-url";
|
|
this.createAssetView = test => {
|
|
const view = new AssetView({model: this.model});
|
|
const requests = test ? AjaxHelpers["requests"](test) : null;
|
|
return {view, requests};
|
|
};
|
|
return done();
|
|
});
|
|
});
|
|
|
|
afterEach(function() {
|
|
this.injector.clean();
|
|
this.injector.remove();
|
|
});
|
|
|
|
describe("Basic", function() {
|
|
it("should render properly", function() {
|
|
let requests;
|
|
({view: this.view, requests} = this.createAssetView());
|
|
this.view.render();
|
|
expect(this.view.$el).toContainText("test asset");
|
|
});
|
|
|
|
it("should pop a delete confirmation when the delete button is clicked", function() {
|
|
let requests;
|
|
({view: this.view, requests} = this.createAssetView());
|
|
this.view.render().$(".remove-asset-button").click();
|
|
expect(this.promptSpies.constructor).toHaveBeenCalled();
|
|
const ctorOptions = this.promptSpies.constructor.calls.mostRecent().args[0];
|
|
expect(ctorOptions.title).toMatch('Delete File Confirmation');
|
|
// hasn't actually been removed
|
|
expect(this.model.destroy).not.toHaveBeenCalled();
|
|
expect(this.collection).toContain(this.model);
|
|
});
|
|
});
|
|
|
|
describe("AJAX", function() {
|
|
it("should destroy itself on confirmation", function() {
|
|
let requests;
|
|
({view: this.view, requests} = this.createAssetView(this));
|
|
|
|
this.view.render().$(".remove-asset-button").click();
|
|
const ctorOptions = this.promptSpies.constructor.calls.mostRecent().args[0];
|
|
// run the primary function to indicate confirmation
|
|
ctorOptions.actions.primary.click(this.promptSpies);
|
|
// AJAX request has been sent, but not yet returned
|
|
expect(this.model.destroy).toHaveBeenCalled();
|
|
expect(requests.length).toEqual(1);
|
|
expect(this.confirmationSpies.constructor).not.toHaveBeenCalled();
|
|
expect(this.collection.contains(this.model)).toBeTruthy();
|
|
// return a success response
|
|
requests[0].respond(204);
|
|
expect(this.confirmationSpies.constructor).toHaveBeenCalled();
|
|
expect(this.confirmationSpies.show).toHaveBeenCalled();
|
|
const savingOptions = this.confirmationSpies.constructor.calls.mostRecent().args[0];
|
|
expect(savingOptions.title).toMatch("Your file has been deleted.");
|
|
expect(this.collection.contains(this.model)).toBeFalsy();
|
|
});
|
|
|
|
it("should not destroy itself if server errors", function() {
|
|
let requests;
|
|
({view: this.view, requests} = this.createAssetView(this));
|
|
|
|
this.view.render().$(".remove-asset-button").click();
|
|
const ctorOptions = this.promptSpies.constructor.calls.mostRecent().args[0];
|
|
// run the primary function to indicate confirmation
|
|
ctorOptions.actions.primary.click(this.promptSpies);
|
|
// AJAX request has been sent, but not yet returned
|
|
expect(this.model.destroy).toHaveBeenCalled();
|
|
// return an error response
|
|
requests[0].respond(404);
|
|
expect(this.confirmationSpies.constructor).not.toHaveBeenCalled();
|
|
expect(this.collection.contains(this.model)).toBeTruthy();
|
|
});
|
|
|
|
it("should lock the asset on confirmation", function() {
|
|
let requests;
|
|
({view: this.view, requests} = this.createAssetView(this));
|
|
|
|
this.view.render().$(".lock-checkbox").click();
|
|
// AJAX request has been sent, but not yet returned
|
|
expect(this.model.save).toHaveBeenCalled();
|
|
expect(requests.length).toEqual(1);
|
|
expect(this.savingSpies.constructor).toHaveBeenCalled();
|
|
expect(this.savingSpies.show).toHaveBeenCalled();
|
|
const savingOptions = this.savingSpies.constructor.calls.mostRecent().args[0];
|
|
expect(savingOptions.title).toMatch("Saving");
|
|
expect(this.model.get("locked")).toBeFalsy();
|
|
// return a success response
|
|
requests[0].respond(204);
|
|
expect(this.savingSpies.hide).toHaveBeenCalled();
|
|
expect(this.model.get("locked")).toBeTruthy();
|
|
});
|
|
|
|
it("should not lock the asset if server errors", function() {
|
|
let requests;
|
|
({view: this.view, requests} = this.createAssetView(this));
|
|
|
|
this.view.render().$(".lock-checkbox").click();
|
|
// return an error response
|
|
requests[0].respond(404);
|
|
// Don't call hide because that closes the notification showing the server error.
|
|
expect(this.savingSpies.hide).not.toHaveBeenCalled();
|
|
expect(this.model.get("locked")).toBeFalsy();
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("Assets view", function() {
|
|
beforeEach(function(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']);
|
|
window.course_location_analytics = jasmine.createSpy();
|
|
appendSetFixtures(sandbox({id: "asset_table_body"}));
|
|
|
|
this.promptSpies = jasmine.createSpyObj('Prompt.Warning', ["constructor", "show", "hide"]);
|
|
this.promptSpies.constructor.and.returnValue(this.promptSpies);
|
|
this.promptSpies.show.and.returnValue(this.promptSpies);
|
|
|
|
this.injector = new Squire();
|
|
this.injector.mock("common/js/components/views/feedback_prompt", {
|
|
"Warning": this.promptSpies.constructor
|
|
});
|
|
|
|
this.mockAsset1 = {
|
|
display_name: "test asset 1",
|
|
url: 'actual_asset_url_1',
|
|
portable_url: 'portable_url_1',
|
|
date_added: 'date_1',
|
|
thumbnail: null,
|
|
id: 'id_1'
|
|
};
|
|
this.mockAsset2 = {
|
|
display_name: "test asset 2",
|
|
url: 'actual_asset_url_2',
|
|
portable_url: 'portable_url_2',
|
|
date_added: 'date_2',
|
|
thumbnail: null,
|
|
id: 'id_2'
|
|
};
|
|
this.mockAssetsResponse = {
|
|
assets: [ this.mockAsset1, this.mockAsset2 ],
|
|
start: 0,
|
|
end: 1,
|
|
page: 0,
|
|
pageSize: 5,
|
|
totalCount: 2
|
|
};
|
|
|
|
this.injector.require(["js/models/asset", "js/collections/asset", "js/views/assets"],
|
|
(AssetModel, AssetCollection, AssetsView) => {
|
|
this.AssetModel = AssetModel;
|
|
this.collection = new AssetCollection();
|
|
this.collection.url = "assets-url";
|
|
this.createAssetsView = test => {
|
|
const requests = AjaxHelpers.requests(test);
|
|
const view = new AssetsView({
|
|
collection: this.collection,
|
|
el: $('#asset_table_body')
|
|
});
|
|
view.render();
|
|
return {view, requests};
|
|
};
|
|
return done();
|
|
});
|
|
|
|
return $.ajax();
|
|
});
|
|
|
|
afterEach(function() {
|
|
delete window.analytics;
|
|
delete window.course_location_analytics;
|
|
|
|
this.injector.clean();
|
|
this.injector.remove();
|
|
});
|
|
|
|
const addMockAsset = function(requests) {
|
|
const model = new this.AssetModel({
|
|
display_name: "new asset",
|
|
url: 'new_actual_asset_url',
|
|
portable_url: 'portable_url',
|
|
date_added: 'date',
|
|
thumbnail: null,
|
|
id: 'idx'
|
|
});
|
|
this.view.addAsset(model);
|
|
return AjaxHelpers.respondWithJson(requests,
|
|
{
|
|
assets: [
|
|
this.mockAsset1, this.mockAsset2,
|
|
{
|
|
display_name: "new asset",
|
|
url: 'new_actual_asset_url',
|
|
portable_url: 'portable_url',
|
|
date_added: 'date',
|
|
thumbnail: null,
|
|
id: 'idx'
|
|
}
|
|
],
|
|
start: 0,
|
|
end: 2,
|
|
page: 0,
|
|
pageSize: 5,
|
|
totalCount: 3
|
|
});
|
|
};
|
|
|
|
|
|
describe("Basic", function() {
|
|
// Separate setup method to work-around mis-parenting of beforeEach methods
|
|
const setup = function(requests) {
|
|
this.view.pagingView.setPage(1);
|
|
return AjaxHelpers.respondWithJson(requests, this.mockAssetsResponse);
|
|
};
|
|
|
|
$.fn.fileupload = () => '';
|
|
|
|
const clickEvent = html_selector => $(html_selector).click();
|
|
|
|
it("should show upload modal on clicking upload asset button", function() {
|
|
let requests;
|
|
({view: this.view, requests} = this.createAssetsView(this));
|
|
spyOn(this.view, "showUploadModal");
|
|
setup.call(this, requests);
|
|
expect(this.view.showUploadModal).not.toHaveBeenCalled();
|
|
this.view.showUploadModal(clickEvent(".upload-button"));
|
|
expect(this.view.showUploadModal).toHaveBeenCalled();
|
|
});
|
|
|
|
it("should show file selection menu on choose file button", function() {
|
|
let requests;
|
|
({view: this.view, requests} = this.createAssetsView(this));
|
|
spyOn(this.view, "showFileSelectionMenu");
|
|
setup.call(this, requests);
|
|
expect(this.view.showFileSelectionMenu).not.toHaveBeenCalled();
|
|
this.view.showFileSelectionMenu(clickEvent(".choose-file-button"));
|
|
expect(this.view.showFileSelectionMenu).toHaveBeenCalled();
|
|
});
|
|
|
|
it("should hide upload modal on clicking close button", function() {
|
|
let requests;
|
|
({view: this.view, requests} = this.createAssetsView(this));
|
|
spyOn(this.view, "hideModal");
|
|
setup.call(this, requests);
|
|
expect(this.view.hideModal).not.toHaveBeenCalled();
|
|
this.view.hideModal(clickEvent(".close-button"));
|
|
expect(this.view.hideModal).toHaveBeenCalled();
|
|
});
|
|
|
|
it("should show a status indicator while loading", function() {
|
|
let requests;
|
|
({view: this.view, requests} = this.createAssetsView(this));
|
|
appendSetFixtures('<div class="ui-loading"/>');
|
|
expect($('.ui-loading').is(':visible')).toBe(true);
|
|
setup.call(this, requests);
|
|
expect($('.ui-loading').is(':visible')).toBe(false);
|
|
});
|
|
|
|
it("should hide the status indicator if an error occurs while loading", function() {
|
|
let requests;
|
|
({view: this.view, requests} = this.createAssetsView(this));
|
|
appendSetFixtures('<div class="ui-loading"/>');
|
|
expect($('.ui-loading').is(':visible')).toBe(true);
|
|
this.view.pagingView.setPage(1);
|
|
AjaxHelpers.respondWithError(requests);
|
|
expect($('.ui-loading').is(':visible')).toBe(false);
|
|
});
|
|
|
|
it("should render both assets", function() {
|
|
let requests;
|
|
({view: this.view, requests} = this.createAssetsView(this));
|
|
setup.call(this, requests);
|
|
expect(this.view.$el).toContainText("test asset 1");
|
|
expect(this.view.$el).toContainText("test asset 2");
|
|
});
|
|
|
|
it("should remove the deleted asset from the view", function() {
|
|
let requests;
|
|
({view: this.view, requests} = this.createAssetsView(this));
|
|
AjaxHelpers.respondWithJson(requests, this.mockAssetsResponse);
|
|
setup.call(this, requests);
|
|
// Delete the 2nd asset with success from server.
|
|
this.view.$(".remove-asset-button")[1].click();
|
|
this.promptSpies.constructor.calls.mostRecent().args[0].actions.primary.click(this.promptSpies);
|
|
AjaxHelpers.respondWithNoContent(requests);
|
|
expect(this.view.$el).toContainText("test asset 1");
|
|
expect(this.view.$el).not.toContainText("test asset 2");
|
|
});
|
|
|
|
it("does not remove asset if deletion failed", function() {
|
|
let requests;
|
|
({view: this.view, requests} = this.createAssetsView(this));
|
|
setup.call(this, requests);
|
|
// Delete the 2nd asset, but mimic a failure from the server.
|
|
this.view.$(".remove-asset-button")[1].click();
|
|
this.promptSpies.constructor.calls.mostRecent().args[0].actions.primary.click(this.promptSpies);
|
|
AjaxHelpers.respondWithError(requests);
|
|
expect(this.view.$el).toContainText("test asset 1");
|
|
expect(this.view.$el).toContainText("test asset 2");
|
|
});
|
|
|
|
it("adds an asset if asset does not already exist", function() {
|
|
let requests;
|
|
({view: this.view, requests} = this.createAssetsView(this));
|
|
setup.call(this, requests);
|
|
addMockAsset.call(this, requests);
|
|
expect(this.view.$el).toContainText("new asset");
|
|
expect(this.collection.models.length).toBe(3);
|
|
});
|
|
|
|
it("does not add an asset if asset already exists", function() {
|
|
let requests;
|
|
({view: this.view, requests} = this.createAssetsView(this));
|
|
setup.call(this, requests);
|
|
spyOn(this.collection, "add").and.callThrough();
|
|
const model = this.collection.models[1];
|
|
this.view.addAsset(model);
|
|
expect(this.collection.add).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe("Sorting", function() {
|
|
// Separate setup method to work-around mis-parenting of beforeEach methods
|
|
const setup = function(requests) {
|
|
this.view.pagingView.setPage(1);
|
|
return AjaxHelpers.respondWithJson(requests, this.mockAssetsResponse);
|
|
};
|
|
|
|
it("should have the correct default sort order", function() {
|
|
let requests;
|
|
({view: this.view, requests} = this.createAssetsView(this));
|
|
setup.call(this, requests);
|
|
expect(this.view.pagingView.sortDisplayName()).toBe("Date Added");
|
|
expect(this.view.collection.sortDirection).toBe("desc");
|
|
});
|
|
|
|
it("should toggle the sort order when clicking on the currently sorted column", function() {
|
|
let requests;
|
|
({view: this.view, requests} = this.createAssetsView(this));
|
|
setup.call(this, requests);
|
|
expect(this.view.pagingView.sortDisplayName()).toBe("Date Added");
|
|
expect(this.view.collection.sortDirection).toBe("desc");
|
|
this.view.$("#js-asset-date-col").click();
|
|
AjaxHelpers.respondWithJson(requests, this.mockAssetsResponse);
|
|
expect(this.view.pagingView.sortDisplayName()).toBe("Date Added");
|
|
expect(this.view.collection.sortDirection).toBe("asc");
|
|
this.view.$("#js-asset-date-col").click();
|
|
AjaxHelpers.respondWithJson(requests, this.mockAssetsResponse);
|
|
expect(this.view.pagingView.sortDisplayName()).toBe("Date Added");
|
|
expect(this.view.collection.sortDirection).toBe("desc");
|
|
});
|
|
|
|
it("should switch the sort order when clicking on a different column", function() {
|
|
let requests;
|
|
({view: this.view, requests} = this.createAssetsView(this));
|
|
setup.call(this, requests);
|
|
this.view.$("#js-asset-name-col").click();
|
|
AjaxHelpers.respondWithJson(requests, this.mockAssetsResponse);
|
|
expect(this.view.pagingView.sortDisplayName()).toBe("Name");
|
|
expect(this.view.collection.sortDirection).toBe("asc");
|
|
this.view.$("#js-asset-name-col").click();
|
|
AjaxHelpers.respondWithJson(requests, this.mockAssetsResponse);
|
|
expect(this.view.pagingView.sortDisplayName()).toBe("Name");
|
|
expect(this.view.collection.sortDirection).toBe("desc");
|
|
});
|
|
|
|
it("should switch sort to most recent date added when a new asset is added", function() {
|
|
let requests;
|
|
({view: this.view, requests} = this.createAssetsView(this));
|
|
setup.call(this, requests);
|
|
this.view.$("#js-asset-name-col").click();
|
|
AjaxHelpers.respondWithJson(requests, this.mockAssetsResponse);
|
|
addMockAsset.call(this, requests);
|
|
AjaxHelpers.respondWithJson(requests, this.mockAssetsResponse);
|
|
expect(this.view.pagingView.sortDisplayName()).toBe("Date Added");
|
|
expect(this.view.collection.sortDirection).toBe("desc");
|
|
});
|
|
});
|
|
});
|
|
});
|