CoffeeScript tests migration: Decaffeinate files
This is running decaffeinate, with no additional cleanup.
This commit is contained in:
committed by
Calen Pennington
parent
5c64da2f63
commit
0880502f26
@@ -1,10 +1,20 @@
|
||||
define ["js/models/course"], (Course) ->
|
||||
describe "Course", ->
|
||||
describe "basic", ->
|
||||
beforeEach ->
|
||||
@model = new Course({
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
define(["js/models/course"], Course =>
|
||||
describe("Course", () =>
|
||||
describe("basic", function() {
|
||||
beforeEach(function() {
|
||||
return this.model = new Course({
|
||||
name: "Greek Hero"
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
it "should take a name argument", ->
|
||||
expect(@model.get("name")).toEqual("Greek Hero")
|
||||
return it("should take a name argument", function() {
|
||||
return expect(this.model.get("name")).toEqual("Greek Hero");
|
||||
});
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
@@ -1,59 +1,74 @@
|
||||
define ["js/models/metadata"], (Metadata) ->
|
||||
describe "Metadata", ->
|
||||
it "knows when the value has not been modified", ->
|
||||
model = new Metadata(
|
||||
{'value': 'original', 'explicitly_set': false})
|
||||
expect(model.isModified()).toBeFalsy()
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
define(["js/models/metadata"], Metadata =>
|
||||
describe("Metadata", function() {
|
||||
it("knows when the value has not been modified", function() {
|
||||
let model = new Metadata(
|
||||
{'value': 'original', 'explicitly_set': false});
|
||||
expect(model.isModified()).toBeFalsy();
|
||||
|
||||
model = new Metadata(
|
||||
{'value': 'original', 'explicitly_set': true})
|
||||
model.setValue('original')
|
||||
expect(model.isModified()).toBeFalsy()
|
||||
{'value': 'original', 'explicitly_set': true});
|
||||
model.setValue('original');
|
||||
return expect(model.isModified()).toBeFalsy();
|
||||
});
|
||||
|
||||
it "knows when the value has been modified", ->
|
||||
model = new Metadata(
|
||||
{'value': 'original', 'explicitly_set': false})
|
||||
model.setValue('original')
|
||||
expect(model.isModified()).toBeTruthy()
|
||||
it("knows when the value has been modified", function() {
|
||||
let model = new Metadata(
|
||||
{'value': 'original', 'explicitly_set': false});
|
||||
model.setValue('original');
|
||||
expect(model.isModified()).toBeTruthy();
|
||||
|
||||
model = new Metadata(
|
||||
{'value': 'original', 'explicitly_set': true})
|
||||
model.setValue('modified')
|
||||
expect(model.isModified()).toBeTruthy()
|
||||
{'value': 'original', 'explicitly_set': true});
|
||||
model.setValue('modified');
|
||||
return expect(model.isModified()).toBeTruthy();
|
||||
});
|
||||
|
||||
it "tracks when values have been explicitly set", ->
|
||||
model = new Metadata(
|
||||
{'value': 'original', 'explicitly_set': false})
|
||||
expect(model.isExplicitlySet()).toBeFalsy()
|
||||
model.setValue('original')
|
||||
expect(model.isExplicitlySet()).toBeTruthy()
|
||||
it("tracks when values have been explicitly set", function() {
|
||||
const model = new Metadata(
|
||||
{'value': 'original', 'explicitly_set': false});
|
||||
expect(model.isExplicitlySet()).toBeFalsy();
|
||||
model.setValue('original');
|
||||
return expect(model.isExplicitlySet()).toBeTruthy();
|
||||
});
|
||||
|
||||
it "has both 'display value' and a 'value' methods", ->
|
||||
model = new Metadata(
|
||||
{'value': 'default', 'explicitly_set': false})
|
||||
expect(model.getValue()).toBeNull
|
||||
expect(model.getDisplayValue()).toBe('default')
|
||||
model.setValue('modified')
|
||||
expect(model.getValue()).toBe('modified')
|
||||
expect(model.getDisplayValue()).toBe('modified')
|
||||
it("has both 'display value' and a 'value' methods", function() {
|
||||
const model = new Metadata(
|
||||
{'value': 'default', 'explicitly_set': false});
|
||||
expect(model.getValue()).toBeNull;
|
||||
expect(model.getDisplayValue()).toBe('default');
|
||||
model.setValue('modified');
|
||||
expect(model.getValue()).toBe('modified');
|
||||
return expect(model.getDisplayValue()).toBe('modified');
|
||||
});
|
||||
|
||||
it "has a clear method for reverting to the default", ->
|
||||
model = new Metadata(
|
||||
{'value': 'original', 'default_value' : 'default', 'explicitly_set': true})
|
||||
model.clear()
|
||||
expect(model.getValue()).toBeNull
|
||||
expect(model.getDisplayValue()).toBe('default')
|
||||
expect(model.isExplicitlySet()).toBeFalsy()
|
||||
it("has a clear method for reverting to the default", function() {
|
||||
const model = new Metadata(
|
||||
{'value': 'original', 'default_value' : 'default', 'explicitly_set': true});
|
||||
model.clear();
|
||||
expect(model.getValue()).toBeNull;
|
||||
expect(model.getDisplayValue()).toBe('default');
|
||||
return expect(model.isExplicitlySet()).toBeFalsy();
|
||||
});
|
||||
|
||||
it "has a getter for field name", ->
|
||||
model = new Metadata({'field_name': 'foo'})
|
||||
expect(model.getFieldName()).toBe('foo')
|
||||
it("has a getter for field name", function() {
|
||||
const model = new Metadata({'field_name': 'foo'});
|
||||
return expect(model.getFieldName()).toBe('foo');
|
||||
});
|
||||
|
||||
it "has a getter for options", ->
|
||||
model = new Metadata({'options': ['foo', 'bar']})
|
||||
expect(model.getOptions()).toEqual(['foo', 'bar'])
|
||||
it("has a getter for options", function() {
|
||||
const model = new Metadata({'options': ['foo', 'bar']});
|
||||
return expect(model.getOptions()).toEqual(['foo', 'bar']);
|
||||
});
|
||||
|
||||
it "has a getter for type", ->
|
||||
model = new Metadata({'type': 'Integer'})
|
||||
expect(model.getType()).toBe(Metadata.INTEGER_TYPE)
|
||||
return it("has a getter for type", function() {
|
||||
const model = new Metadata({'type': 'Integer'});
|
||||
return expect(model.getType()).toBe(Metadata.INTEGER_TYPE);
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
@@ -1,50 +1,67 @@
|
||||
define ["js/models/section", "edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers", "js/utils/module"], (Section, AjaxHelpers, ModuleUtils) ->
|
||||
describe "Section", ->
|
||||
describe "basic", ->
|
||||
beforeEach ->
|
||||
@model = new Section({
|
||||
id: 42
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
define(["js/models/section", "edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers", "js/utils/module"], (Section, AjaxHelpers, ModuleUtils) =>
|
||||
describe("Section", function() {
|
||||
describe("basic", function() {
|
||||
beforeEach(function() {
|
||||
return this.model = new Section({
|
||||
id: 42,
|
||||
name: "Life, the Universe, and Everything"
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
it "should take an id argument", ->
|
||||
expect(@model.get("id")).toEqual(42)
|
||||
it("should take an id argument", function() {
|
||||
return expect(this.model.get("id")).toEqual(42);
|
||||
});
|
||||
|
||||
it "should take a name argument", ->
|
||||
expect(@model.get("name")).toEqual("Life, the Universe, and Everything")
|
||||
it("should take a name argument", function() {
|
||||
return expect(this.model.get("name")).toEqual("Life, the Universe, and Everything");
|
||||
});
|
||||
|
||||
it "should have a URL set", ->
|
||||
expect(@model.url()).toEqual(ModuleUtils.getUpdateUrl(42))
|
||||
it("should have a URL set", function() {
|
||||
return expect(this.model.url()).toEqual(ModuleUtils.getUpdateUrl(42));
|
||||
});
|
||||
|
||||
it "should serialize to JSON correctly", ->
|
||||
expect(@model.toJSON()).toEqual({
|
||||
return it("should serialize to JSON correctly", function() {
|
||||
return expect(this.model.toJSON()).toEqual({
|
||||
metadata:
|
||||
{
|
||||
display_name: "Life, the Universe, and Everything"
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe "XHR", ->
|
||||
beforeEach ->
|
||||
spyOn(Section.prototype, 'showNotification')
|
||||
spyOn(Section.prototype, 'hideNotification')
|
||||
@model = new Section({
|
||||
id: 42
|
||||
return describe("XHR", function() {
|
||||
beforeEach(function() {
|
||||
spyOn(Section.prototype, 'showNotification');
|
||||
spyOn(Section.prototype, 'hideNotification');
|
||||
return this.model = new Section({
|
||||
id: 42,
|
||||
name: "Life, the Universe, and Everything"
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
it "show/hide a notification when it saves to the server", ->
|
||||
server = AjaxHelpers.server([200, {"Content-Type": "application/json"}, "{}"])
|
||||
it("show/hide a notification when it saves to the server", function() {
|
||||
const server = AjaxHelpers.server([200, {"Content-Type": "application/json"}, "{}"]);
|
||||
|
||||
@model.save()
|
||||
expect(Section.prototype.showNotification).toHaveBeenCalled()
|
||||
server.respond()
|
||||
expect(Section.prototype.hideNotification).toHaveBeenCalled()
|
||||
this.model.save();
|
||||
expect(Section.prototype.showNotification).toHaveBeenCalled();
|
||||
server.respond();
|
||||
return expect(Section.prototype.hideNotification).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it "don't hide notification when saving fails", ->
|
||||
# this is handled by the global AJAX error handler
|
||||
server = AjaxHelpers.server([500, {"Content-Type": "application/json"}, "{}"])
|
||||
return it("don't hide notification when saving fails", function() {
|
||||
// this is handled by the global AJAX error handler
|
||||
const server = AjaxHelpers.server([500, {"Content-Type": "application/json"}, "{}"]);
|
||||
|
||||
@model.save()
|
||||
server.respond()
|
||||
expect(Section.prototype.hideNotification).not.toHaveBeenCalled()
|
||||
this.model.save();
|
||||
server.respond();
|
||||
return expect(Section.prototype.hideNotification).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
@@ -1,39 +1,52 @@
|
||||
define ["js/models/settings/course_grader"], (CourseGrader) ->
|
||||
describe "CourseGraderModel", ->
|
||||
describe "parseWeight", ->
|
||||
it "converts a float to an integer", ->
|
||||
model = new CourseGrader({weight: 7.0001, min_count: 3.67, drop_count: 1.88}, {parse:true})
|
||||
expect(model.get('weight')).toBe(7)
|
||||
expect(model.get('min_count')).toBe(4)
|
||||
expect(model.get('drop_count')).toBe(2)
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
define(["js/models/settings/course_grader"], CourseGrader =>
|
||||
describe("CourseGraderModel", () =>
|
||||
describe("parseWeight", function() {
|
||||
it("converts a float to an integer", function() {
|
||||
const model = new CourseGrader({weight: 7.0001, min_count: 3.67, drop_count: 1.88}, {parse:true});
|
||||
expect(model.get('weight')).toBe(7);
|
||||
expect(model.get('min_count')).toBe(4);
|
||||
return expect(model.get('drop_count')).toBe(2);
|
||||
});
|
||||
|
||||
it "converts float value of weight to an integer with rounding", ->
|
||||
model = new CourseGrader({weight: 28.999999999999996}, {parse:true})
|
||||
expect(model.get('weight')).toBe(29)
|
||||
it("converts float value of weight to an integer with rounding", function() {
|
||||
const model = new CourseGrader({weight: 28.999999999999996}, {parse:true});
|
||||
return expect(model.get('weight')).toBe(29);
|
||||
});
|
||||
|
||||
it "converts a string to an integer", ->
|
||||
model = new CourseGrader({weight: '7.0001', min_count: '3.67', drop_count: '1.88'}, {parse:true})
|
||||
expect(model.get('weight')).toBe(7)
|
||||
expect(model.get('min_count')).toBe(4)
|
||||
expect(model.get('drop_count')).toBe(2)
|
||||
it("converts a string to an integer", function() {
|
||||
const model = new CourseGrader({weight: '7.0001', min_count: '3.67', drop_count: '1.88'}, {parse:true});
|
||||
expect(model.get('weight')).toBe(7);
|
||||
expect(model.get('min_count')).toBe(4);
|
||||
return expect(model.get('drop_count')).toBe(2);
|
||||
});
|
||||
|
||||
it "does a no-op for integers", ->
|
||||
model = new CourseGrader({weight: 7, min_count: 3, drop_count: 1}, {parse:true})
|
||||
expect(model.get('weight')).toBe(7)
|
||||
expect(model.get('min_count')).toBe(3)
|
||||
expect(model.get('drop_count')).toBe(1)
|
||||
it("does a no-op for integers", function() {
|
||||
const model = new CourseGrader({weight: 7, min_count: 3, drop_count: 1}, {parse:true});
|
||||
expect(model.get('weight')).toBe(7);
|
||||
expect(model.get('min_count')).toBe(3);
|
||||
return expect(model.get('drop_count')).toBe(1);
|
||||
});
|
||||
|
||||
it "gives validation error if min_count is less than 1 or drop_count is NaN", ->
|
||||
model = new CourseGrader()
|
||||
errors = model.validate({min_count: 0, drop_count: ''}, {validate:true})
|
||||
expect(errors.min_count).toBe('Please enter an integer greater than 0.')
|
||||
expect(errors.drop_count).toBe('Please enter non-negative integer.')
|
||||
# don't allow negative integers
|
||||
errors = model.validate({min_count: -12, drop_count: -1}, {validate:true})
|
||||
expect(errors.min_count).toBe('Please enter an integer greater than 0.')
|
||||
expect(errors.drop_count).toBe('Please enter non-negative integer.')
|
||||
# don't allow floats
|
||||
errors = model.validate({min_count: 12.2, drop_count: 1.5}, {validate:true})
|
||||
expect(errors.min_count).toBe('Please enter an integer greater than 0.')
|
||||
expect(errors.drop_count).toBe('Please enter non-negative integer.')
|
||||
return it("gives validation error if min_count is less than 1 or drop_count is NaN", function() {
|
||||
const model = new CourseGrader();
|
||||
let errors = model.validate({min_count: 0, drop_count: ''}, {validate:true});
|
||||
expect(errors.min_count).toBe('Please enter an integer greater than 0.');
|
||||
expect(errors.drop_count).toBe('Please enter non-negative integer.');
|
||||
// don't allow negative integers
|
||||
errors = model.validate({min_count: -12, drop_count: -1}, {validate:true});
|
||||
expect(errors.min_count).toBe('Please enter an integer greater than 0.');
|
||||
expect(errors.drop_count).toBe('Please enter non-negative integer.');
|
||||
// don't allow floats
|
||||
errors = model.validate({min_count: 12.2, drop_count: 1.5}, {validate:true});
|
||||
expect(errors.min_count).toBe('Please enter an integer greater than 0.');
|
||||
return expect(errors.drop_count).toBe('Please enter non-negative integer.');
|
||||
});
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -1,36 +1,52 @@
|
||||
define ["underscore", "js/models/settings/course_grading_policy"], (_, CourseGradingPolicy) ->
|
||||
describe "CourseGradingPolicy", ->
|
||||
beforeEach ->
|
||||
@model = new CourseGradingPolicy()
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
define(["underscore", "js/models/settings/course_grading_policy"], (_, CourseGradingPolicy) =>
|
||||
describe("CourseGradingPolicy", function() {
|
||||
beforeEach(function() {
|
||||
return this.model = new CourseGradingPolicy();
|
||||
});
|
||||
|
||||
describe "parse", ->
|
||||
it "sets a null grace period to 00:00", ->
|
||||
attrs = @model.parse(grace_period: null)
|
||||
expect(attrs.grace_period).toEqual(
|
||||
describe("parse", () =>
|
||||
it("sets a null grace period to 00:00", function() {
|
||||
const attrs = this.model.parse({grace_period: null});
|
||||
return expect(attrs.grace_period).toEqual({
|
||||
hours: 0,
|
||||
minutes: 0
|
||||
)
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
describe "parseGracePeriod", ->
|
||||
it "parses a time in HH:MM format", ->
|
||||
time = @model.parseGracePeriod("07:19")
|
||||
expect(time).toEqual(
|
||||
describe("parseGracePeriod", function() {
|
||||
it("parses a time in HH:MM format", function() {
|
||||
const time = this.model.parseGracePeriod("07:19");
|
||||
return expect(time).toEqual({
|
||||
hours: 7,
|
||||
minutes: 19
|
||||
)
|
||||
});
|
||||
});
|
||||
|
||||
it "returns null on an incorrectly formatted string", ->
|
||||
expect(@model.parseGracePeriod("asdf")).toBe(null)
|
||||
expect(@model.parseGracePeriod("7:19")).toBe(null)
|
||||
expect(@model.parseGracePeriod("1000:00")).toBe(null)
|
||||
return it("returns null on an incorrectly formatted string", function() {
|
||||
expect(this.model.parseGracePeriod("asdf")).toBe(null);
|
||||
expect(this.model.parseGracePeriod("7:19")).toBe(null);
|
||||
return expect(this.model.parseGracePeriod("1000:00")).toBe(null);
|
||||
});
|
||||
});
|
||||
|
||||
describe "validate", ->
|
||||
it "enforces that the passing grade is <= the minimum grade to receive credit if credit is enabled", ->
|
||||
@model.set({minimum_grade_credit: 0.8, grace_period: '01:00', is_credit_course: true})
|
||||
@model.set('grade_cutoffs', [0.9], validate: true)
|
||||
expect(_.keys(@model.validationError)).toContain('minimum_grade_credit')
|
||||
return describe("validate", function() {
|
||||
it("enforces that the passing grade is <= the minimum grade to receive credit if credit is enabled", function() {
|
||||
this.model.set({minimum_grade_credit: 0.8, grace_period: '01:00', is_credit_course: true});
|
||||
this.model.set('grade_cutoffs', [0.9], {validate: true});
|
||||
return expect(_.keys(this.model.validationError)).toContain('minimum_grade_credit');
|
||||
});
|
||||
|
||||
it "does not enforce the passing grade limit in non-credit courses", ->
|
||||
@model.set({minimum_grade_credit: 0.8, grace_period: '01:00', is_credit_course: false})
|
||||
@model.set({grade_cutoffs: [0.9]}, validate: true)
|
||||
expect(@model.validationError).toBe(null)
|
||||
return it("does not enforce the passing grade limit in non-credit courses", function() {
|
||||
this.model.set({minimum_grade_credit: 0.8, grace_period: '01:00', is_credit_course: false});
|
||||
this.model.set({grade_cutoffs: [0.9]}, {validate: true});
|
||||
return expect(this.model.validationError).toBe(null);
|
||||
});
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
@@ -1,78 +1,98 @@
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS203: Remove `|| {}` from converted for-own loops
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
|
||||
define ["backbone", "js/models/textbook", "js/collections/textbook", "js/models/chapter", "js/collections/chapter", "cms/js/main"],
|
||||
(Backbone, Textbook, TextbookSet, Chapter, ChapterSet, main) ->
|
||||
define(["backbone", "js/models/textbook", "js/collections/textbook", "js/models/chapter", "js/collections/chapter", "cms/js/main"],
|
||||
function(Backbone, Textbook, TextbookSet, Chapter, ChapterSet, main) {
|
||||
|
||||
describe "Textbook model", ->
|
||||
beforeEach ->
|
||||
main()
|
||||
@model = new Textbook()
|
||||
CMS.URL.TEXTBOOKS = "/textbooks"
|
||||
describe("Textbook model", function() {
|
||||
beforeEach(function() {
|
||||
main();
|
||||
this.model = new Textbook();
|
||||
return CMS.URL.TEXTBOOKS = "/textbooks";
|
||||
});
|
||||
|
||||
afterEach ->
|
||||
delete CMS.URL.TEXTBOOKS
|
||||
afterEach(() => delete CMS.URL.TEXTBOOKS);
|
||||
|
||||
describe "Basic", ->
|
||||
it "should have an empty name by default", ->
|
||||
expect(@model.get("name")).toEqual("")
|
||||
describe("Basic", function() {
|
||||
it("should have an empty name by default", function() {
|
||||
return expect(this.model.get("name")).toEqual("");
|
||||
});
|
||||
|
||||
it "should not show chapters by default", ->
|
||||
expect(@model.get("showChapters")).toBeFalsy()
|
||||
it("should not show chapters by default", function() {
|
||||
return expect(this.model.get("showChapters")).toBeFalsy();
|
||||
});
|
||||
|
||||
it "should have a ChapterSet with one chapter by default", ->
|
||||
chapters = @model.get("chapters")
|
||||
expect(chapters).toBeInstanceOf(ChapterSet)
|
||||
expect(chapters.length).toEqual(1)
|
||||
expect(chapters.at(0).isEmpty()).toBeTruthy()
|
||||
it("should have a ChapterSet with one chapter by default", function() {
|
||||
const chapters = this.model.get("chapters");
|
||||
expect(chapters).toBeInstanceOf(ChapterSet);
|
||||
expect(chapters.length).toEqual(1);
|
||||
return expect(chapters.at(0).isEmpty()).toBeTruthy();
|
||||
});
|
||||
|
||||
it "should be empty by default", ->
|
||||
expect(@model.isEmpty()).toBeTruthy()
|
||||
it("should be empty by default", function() {
|
||||
return expect(this.model.isEmpty()).toBeTruthy();
|
||||
});
|
||||
|
||||
it "should have a URL root", ->
|
||||
urlRoot = _.result(@model, 'urlRoot')
|
||||
expect(urlRoot).toBeTruthy()
|
||||
it("should have a URL root", function() {
|
||||
const urlRoot = _.result(this.model, 'urlRoot');
|
||||
return expect(urlRoot).toBeTruthy();
|
||||
});
|
||||
|
||||
it "should be able to reset itself", ->
|
||||
@model.set("name", "foobar")
|
||||
@model.reset()
|
||||
expect(@model.get("name")).toEqual("")
|
||||
it("should be able to reset itself", function() {
|
||||
this.model.set("name", "foobar");
|
||||
this.model.reset();
|
||||
return expect(this.model.get("name")).toEqual("");
|
||||
});
|
||||
|
||||
it "should not be dirty by default", ->
|
||||
expect(@model.isDirty()).toBeFalsy()
|
||||
it("should not be dirty by default", function() {
|
||||
return expect(this.model.isDirty()).toBeFalsy();
|
||||
});
|
||||
|
||||
it "should be dirty after it's been changed", ->
|
||||
@model.set("name", "foobar")
|
||||
expect(@model.isDirty()).toBeTruthy()
|
||||
it("should be dirty after it's been changed", function() {
|
||||
this.model.set("name", "foobar");
|
||||
return expect(this.model.isDirty()).toBeTruthy();
|
||||
});
|
||||
|
||||
it "should not be dirty after calling setOriginalAttributes", ->
|
||||
@model.set("name", "foobar")
|
||||
@model.setOriginalAttributes()
|
||||
expect(@model.isDirty()).toBeFalsy()
|
||||
return it("should not be dirty after calling setOriginalAttributes", function() {
|
||||
this.model.set("name", "foobar");
|
||||
this.model.setOriginalAttributes();
|
||||
return expect(this.model.isDirty()).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe "Input/Output", ->
|
||||
deepAttributes = (obj) ->
|
||||
if obj instanceof Backbone.Model
|
||||
deepAttributes(obj.attributes)
|
||||
else if obj instanceof Backbone.Collection
|
||||
obj.map(deepAttributes);
|
||||
else if _.isArray(obj)
|
||||
_.map(obj, deepAttributes);
|
||||
else if _.isObject(obj)
|
||||
attributes = {};
|
||||
for own prop, val of obj
|
||||
attributes[prop] = deepAttributes(val)
|
||||
attributes
|
||||
else
|
||||
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 (_.isArray(obj)) {
|
||||
return _.map(obj, deepAttributes);
|
||||
} else if (_.isObject(obj)) {
|
||||
const attributes = {};
|
||||
for (let prop of Object.keys(obj || {})) {
|
||||
const val = obj[prop];
|
||||
attributes[prop] = deepAttributes(val);
|
||||
}
|
||||
return attributes;
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
|
||||
it "should match server model to client model", ->
|
||||
serverModelSpec = {
|
||||
return it("should match server model to client model", function() {
|
||||
const serverModelSpec = {
|
||||
"tab_title": "My Textbook",
|
||||
"chapters": [
|
||||
{"title": "Chapter 1", "url": "/ch1.pdf"},
|
||||
{"title": "Chapter 2", "url": "/ch2.pdf"},
|
||||
]
|
||||
}
|
||||
clientModelSpec = {
|
||||
};
|
||||
const clientModelSpec = {
|
||||
"name": "My Textbook",
|
||||
"showChapters": false,
|
||||
"editing": false,
|
||||
@@ -86,113 +106,142 @@ define ["backbone", "js/models/textbook", "js/collections/textbook", "js/models/
|
||||
"order": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
model = new Textbook(serverModelSpec, {parse: true})
|
||||
expect(deepAttributes(model)).toEqual(clientModelSpec)
|
||||
expect(model.toJSON()).toEqual(serverModelSpec)
|
||||
const model = new Textbook(serverModelSpec, {parse: true});
|
||||
expect(deepAttributes(model)).toEqual(clientModelSpec);
|
||||
return expect(model.toJSON()).toEqual(serverModelSpec);
|
||||
});
|
||||
});
|
||||
|
||||
describe "Validation", ->
|
||||
it "requires a name", ->
|
||||
model = new Textbook({name: ""})
|
||||
expect(model.isValid()).toBeFalsy()
|
||||
return describe("Validation", function() {
|
||||
it("requires a name", function() {
|
||||
const model = new Textbook({name: ""});
|
||||
return expect(model.isValid()).toBeFalsy();
|
||||
});
|
||||
|
||||
it "requires at least one chapter", ->
|
||||
model = new Textbook({name: "foo"})
|
||||
model.get("chapters").reset()
|
||||
expect(model.isValid()).toBeFalsy()
|
||||
it("requires at least one chapter", function() {
|
||||
const model = new Textbook({name: "foo"});
|
||||
model.get("chapters").reset();
|
||||
return expect(model.isValid()).toBeFalsy();
|
||||
});
|
||||
|
||||
it "requires a valid chapter", ->
|
||||
chapter = new Chapter()
|
||||
chapter.isValid = -> false
|
||||
model = new Textbook({name: "foo"})
|
||||
model.get("chapters").reset([chapter])
|
||||
expect(model.isValid()).toBeFalsy()
|
||||
it("requires a valid chapter", function() {
|
||||
const chapter = new Chapter();
|
||||
chapter.isValid = () => false;
|
||||
const model = new Textbook({name: "foo"});
|
||||
model.get("chapters").reset([chapter]);
|
||||
return expect(model.isValid()).toBeFalsy();
|
||||
});
|
||||
|
||||
it "requires all chapters to be valid", ->
|
||||
chapter1 = new Chapter()
|
||||
chapter1.isValid = -> true
|
||||
chapter2 = new Chapter()
|
||||
chapter2.isValid = -> false
|
||||
model = new Textbook({name: "foo"})
|
||||
model.get("chapters").reset([chapter1, chapter2])
|
||||
expect(model.isValid()).toBeFalsy()
|
||||
it("requires all chapters to be valid", function() {
|
||||
const chapter1 = new Chapter();
|
||||
chapter1.isValid = () => true;
|
||||
const chapter2 = new Chapter();
|
||||
chapter2.isValid = () => false;
|
||||
const model = new Textbook({name: "foo"});
|
||||
model.get("chapters").reset([chapter1, chapter2]);
|
||||
return expect(model.isValid()).toBeFalsy();
|
||||
});
|
||||
|
||||
it "can pass validation", ->
|
||||
chapter = new Chapter()
|
||||
chapter.isValid = -> true
|
||||
model = new Textbook({name: "foo"})
|
||||
model.get("chapters").reset([chapter])
|
||||
expect(model.isValid()).toBeTruthy()
|
||||
return it("can pass validation", function() {
|
||||
const chapter = new Chapter();
|
||||
chapter.isValid = () => true;
|
||||
const model = new Textbook({name: "foo"});
|
||||
model.get("chapters").reset([chapter]);
|
||||
return expect(model.isValid()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe "Textbook collection", ->
|
||||
beforeEach ->
|
||||
CMS.URL.TEXTBOOKS = "/textbooks"
|
||||
@collection = new TextbookSet()
|
||||
describe("Textbook collection", function() {
|
||||
beforeEach(function() {
|
||||
CMS.URL.TEXTBOOKS = "/textbooks";
|
||||
return this.collection = new TextbookSet();
|
||||
});
|
||||
|
||||
afterEach ->
|
||||
delete CMS.URL.TEXTBOOKS
|
||||
afterEach(() => delete CMS.URL.TEXTBOOKS);
|
||||
|
||||
it "should have a url set", ->
|
||||
url = _.result(@collection, 'url')
|
||||
expect(url).toEqual("/textbooks")
|
||||
return it("should have a url set", function() {
|
||||
const url = _.result(this.collection, 'url');
|
||||
return expect(url).toEqual("/textbooks");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe "Chapter model", ->
|
||||
beforeEach ->
|
||||
@model = new Chapter()
|
||||
describe("Chapter model", function() {
|
||||
beforeEach(function() {
|
||||
return this.model = new Chapter();
|
||||
});
|
||||
|
||||
describe "Basic", ->
|
||||
it "should have a name by default", ->
|
||||
expect(@model.get("name")).toEqual("")
|
||||
describe("Basic", function() {
|
||||
it("should have a name by default", function() {
|
||||
return expect(this.model.get("name")).toEqual("");
|
||||
});
|
||||
|
||||
it "should have an asset_path by default", ->
|
||||
expect(@model.get("asset_path")).toEqual("")
|
||||
it("should have an asset_path by default", function() {
|
||||
return expect(this.model.get("asset_path")).toEqual("");
|
||||
});
|
||||
|
||||
it "should have an order by default", ->
|
||||
expect(@model.get("order")).toEqual(1)
|
||||
it("should have an order by default", function() {
|
||||
return expect(this.model.get("order")).toEqual(1);
|
||||
});
|
||||
|
||||
it "should be empty by default", ->
|
||||
expect(@model.isEmpty()).toBeTruthy()
|
||||
return it("should be empty by default", function() {
|
||||
return expect(this.model.isEmpty()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe "Validation", ->
|
||||
it "requires a name", ->
|
||||
model = new Chapter({name: "", asset_path: "a.pdf"})
|
||||
expect(model.isValid()).toBeFalsy()
|
||||
return describe("Validation", function() {
|
||||
it("requires a name", function() {
|
||||
const model = new Chapter({name: "", asset_path: "a.pdf"});
|
||||
return expect(model.isValid()).toBeFalsy();
|
||||
});
|
||||
|
||||
it "requires an asset_path", ->
|
||||
model = new Chapter({name: "a", asset_path: ""})
|
||||
expect(model.isValid()).toBeFalsy()
|
||||
it("requires an asset_path", function() {
|
||||
const model = new Chapter({name: "a", asset_path: ""});
|
||||
return expect(model.isValid()).toBeFalsy();
|
||||
});
|
||||
|
||||
it "can pass validation", ->
|
||||
model = new Chapter({name: "a", asset_path: "a.pdf"})
|
||||
expect(model.isValid()).toBeTruthy()
|
||||
return it("can pass validation", function() {
|
||||
const model = new Chapter({name: "a", asset_path: "a.pdf"});
|
||||
return expect(model.isValid()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe "Chapter collection", ->
|
||||
beforeEach ->
|
||||
@collection = new ChapterSet()
|
||||
return describe("Chapter collection", function() {
|
||||
beforeEach(function() {
|
||||
return this.collection = new ChapterSet();
|
||||
});
|
||||
|
||||
it "is empty by default", ->
|
||||
expect(@collection.isEmpty()).toBeTruthy()
|
||||
it("is empty by default", function() {
|
||||
return expect(this.collection.isEmpty()).toBeTruthy();
|
||||
});
|
||||
|
||||
it "is empty if all chapters are empty", ->
|
||||
@collection.add([{}, {}, {}])
|
||||
expect(@collection.isEmpty()).toBeTruthy()
|
||||
it("is empty if all chapters are empty", function() {
|
||||
this.collection.add([{}, {}, {}]);
|
||||
return expect(this.collection.isEmpty()).toBeTruthy();
|
||||
});
|
||||
|
||||
it "is not empty if a chapter is not empty", ->
|
||||
@collection.add([{}, {name: "full"}, {}])
|
||||
expect(@collection.isEmpty()).toBeFalsy()
|
||||
it("is not empty if a chapter is not empty", function() {
|
||||
this.collection.add([{}, {name: "full"}, {}]);
|
||||
return expect(this.collection.isEmpty()).toBeFalsy();
|
||||
});
|
||||
|
||||
it "should have a nextOrder function", ->
|
||||
expect(@collection.nextOrder()).toEqual(1)
|
||||
@collection.add([{}])
|
||||
expect(@collection.nextOrder()).toEqual(2)
|
||||
@collection.add([{}])
|
||||
expect(@collection.nextOrder()).toEqual(3)
|
||||
# verify that it doesn't just return an incrementing value each time
|
||||
expect(@collection.nextOrder()).toEqual(3)
|
||||
# try going back one
|
||||
@collection.remove(@collection.last())
|
||||
expect(@collection.nextOrder()).toEqual(2)
|
||||
return it("should have a nextOrder function", function() {
|
||||
expect(this.collection.nextOrder()).toEqual(1);
|
||||
this.collection.add([{}]);
|
||||
expect(this.collection.nextOrder()).toEqual(2);
|
||||
this.collection.add([{}]);
|
||||
expect(this.collection.nextOrder()).toEqual(3);
|
||||
// verify that it doesn't just return an incrementing value each time
|
||||
expect(this.collection.nextOrder()).toEqual(3);
|
||||
// try going back one
|
||||
this.collection.remove(this.collection.last());
|
||||
return expect(this.collection.nextOrder()).toEqual(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,71 +1,93 @@
|
||||
define ["js/models/uploads"], (FileUpload) ->
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
define(["js/models/uploads"], FileUpload =>
|
||||
|
||||
describe "FileUpload", ->
|
||||
beforeEach ->
|
||||
@model = new FileUpload()
|
||||
describe("FileUpload", function() {
|
||||
beforeEach(function() {
|
||||
return this.model = new FileUpload();
|
||||
});
|
||||
|
||||
it "is unfinished by default", ->
|
||||
expect(@model.get("finished")).toBeFalsy()
|
||||
it("is unfinished by default", function() {
|
||||
return expect(this.model.get("finished")).toBeFalsy();
|
||||
});
|
||||
|
||||
it "is not uploading by default", ->
|
||||
expect(@model.get("uploading")).toBeFalsy()
|
||||
it("is not uploading by default", function() {
|
||||
return expect(this.model.get("uploading")).toBeFalsy();
|
||||
});
|
||||
|
||||
it "is valid by default", ->
|
||||
expect(@model.isValid()).toBeTruthy()
|
||||
it("is valid by default", function() {
|
||||
return expect(this.model.isValid()).toBeTruthy();
|
||||
});
|
||||
|
||||
it "is valid for text files by default", ->
|
||||
file = {"type": "text/plain", "name": "filename.txt"}
|
||||
@model.set("selectedFile", file);
|
||||
expect(@model.isValid()).toBeTruthy()
|
||||
it("is valid for text files by default", function() {
|
||||
const file = {"type": "text/plain", "name": "filename.txt"};
|
||||
this.model.set("selectedFile", file);
|
||||
return expect(this.model.isValid()).toBeTruthy();
|
||||
});
|
||||
|
||||
it "is valid for PNG files by default", ->
|
||||
file = {"type": "image/png", "name": "filename.png"}
|
||||
@model.set("selectedFile", file);
|
||||
expect(@model.isValid()).toBeTruthy()
|
||||
it("is valid for PNG files by default", function() {
|
||||
const file = {"type": "image/png", "name": "filename.png"};
|
||||
this.model.set("selectedFile", file);
|
||||
return expect(this.model.isValid()).toBeTruthy();
|
||||
});
|
||||
|
||||
it "can accept a file type when explicitly set", ->
|
||||
file = {"type": "image/png", "name": "filename.png"}
|
||||
@model.set("mimeTypes": ["image/png"])
|
||||
@model.set("selectedFile", file)
|
||||
expect(@model.isValid()).toBeTruthy()
|
||||
it("can accept a file type when explicitly set", function() {
|
||||
const file = {"type": "image/png", "name": "filename.png"};
|
||||
this.model.set({"mimeTypes": ["image/png"]});
|
||||
this.model.set("selectedFile", file);
|
||||
return expect(this.model.isValid()).toBeTruthy();
|
||||
});
|
||||
|
||||
it "can accept a file format when explicitly set", ->
|
||||
file = {"type": "", "name": "filename.png"}
|
||||
@model.set("fileFormats": ["png"])
|
||||
@model.set("selectedFile", file)
|
||||
expect(@model.isValid()).toBeTruthy()
|
||||
it("can accept a file format when explicitly set", function() {
|
||||
const file = {"type": "", "name": "filename.png"};
|
||||
this.model.set({"fileFormats": ["png"]});
|
||||
this.model.set("selectedFile", file);
|
||||
return expect(this.model.isValid()).toBeTruthy();
|
||||
});
|
||||
|
||||
it "can accept multiple file types", ->
|
||||
file = {"type": "image/gif", "name": "filename.gif"}
|
||||
@model.set("mimeTypes": ["image/png", "image/jpeg", "image/gif"])
|
||||
@model.set("selectedFile", file)
|
||||
expect(@model.isValid()).toBeTruthy()
|
||||
it("can accept multiple file types", function() {
|
||||
const file = {"type": "image/gif", "name": "filename.gif"};
|
||||
this.model.set({"mimeTypes": ["image/png", "image/jpeg", "image/gif"]});
|
||||
this.model.set("selectedFile", file);
|
||||
return expect(this.model.isValid()).toBeTruthy();
|
||||
});
|
||||
|
||||
it "can accept multiple file formats", ->
|
||||
file = {"type": "image/gif", "name": "filename.gif"}
|
||||
@model.set("fileFormats": ["png", "jpeg", "gif"])
|
||||
@model.set("selectedFile", file)
|
||||
expect(@model.isValid()).toBeTruthy()
|
||||
it("can accept multiple file formats", function() {
|
||||
const file = {"type": "image/gif", "name": "filename.gif"};
|
||||
this.model.set({"fileFormats": ["png", "jpeg", "gif"]});
|
||||
this.model.set("selectedFile", file);
|
||||
return expect(this.model.isValid()).toBeTruthy();
|
||||
});
|
||||
|
||||
describe "fileTypes", ->
|
||||
it "returns a list of the uploader's file types", ->
|
||||
@model.set('mimeTypes', ['image/png', 'application/json'])
|
||||
@model.set('fileFormats', ['gif', 'srt'])
|
||||
expect(@model.fileTypes()).toEqual(['PNG', 'JSON', 'GIF', 'SRT'])
|
||||
describe("fileTypes", () =>
|
||||
it("returns a list of the uploader's file types", function() {
|
||||
this.model.set('mimeTypes', ['image/png', 'application/json']);
|
||||
this.model.set('fileFormats', ['gif', 'srt']);
|
||||
return expect(this.model.fileTypes()).toEqual(['PNG', 'JSON', 'GIF', 'SRT']);
|
||||
})
|
||||
);
|
||||
|
||||
describe "formatValidTypes", ->
|
||||
it "returns a map of formatted file types and extensions", ->
|
||||
@model.set('mimeTypes', ['image/png', 'image/jpeg', 'application/json'])
|
||||
formatted = @model.formatValidTypes()
|
||||
expect(formatted).toEqual(
|
||||
return describe("formatValidTypes", function() {
|
||||
it("returns a map of formatted file types and extensions", function() {
|
||||
this.model.set('mimeTypes', ['image/png', 'image/jpeg', 'application/json']);
|
||||
const formatted = this.model.formatValidTypes();
|
||||
return expect(formatted).toEqual({
|
||||
fileTypes: 'PNG, JPEG or JSON',
|
||||
fileExtensions: '.png, .jpeg or .json'
|
||||
)
|
||||
});
|
||||
});
|
||||
|
||||
it "does not format with only one mime type", ->
|
||||
@model.set('mimeTypes', ['application/pdf'])
|
||||
formatted = @model.formatValidTypes()
|
||||
expect(formatted).toEqual(
|
||||
return it("does not format with only one mime type", function() {
|
||||
this.model.set('mimeTypes', ['application/pdf']);
|
||||
const formatted = this.model.formatValidTypes();
|
||||
return expect(formatted).toEqual({
|
||||
fileTypes: 'PDF',
|
||||
fileExtensions: '.pdf'
|
||||
)
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
@@ -1,221 +1,252 @@
|
||||
define ["jquery", "edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers", "squire"],
|
||||
($, AjaxHelpers, Squire) ->
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
define(["jquery", "edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers", "squire"],
|
||||
function($, AjaxHelpers, Squire) {
|
||||
|
||||
assetLibraryTpl = readFixtures('asset-library.underscore')
|
||||
assetTpl = readFixtures('asset.underscore')
|
||||
const assetLibraryTpl = readFixtures('asset-library.underscore');
|
||||
const assetTpl = readFixtures('asset.underscore');
|
||||
|
||||
describe "Asset view", ->
|
||||
beforeEach (done) ->
|
||||
setFixtures($("<script>", {id: "asset-tpl", type: "text/template"}).text(assetTpl))
|
||||
appendSetFixtures(sandbox({id: "page-prompt"}))
|
||||
describe("Asset view", function() {
|
||||
beforeEach(function(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.and.returnValue(@promptSpies)
|
||||
@promptSpies.show.and.returnValue(@promptSpies)
|
||||
this.promptSpies = jasmine.createSpyObj('Prompt.Warning', ["constructor", "show", "hide"]);
|
||||
this.promptSpies.constructor.and.returnValue(this.promptSpies);
|
||||
this.promptSpies.show.and.returnValue(this.promptSpies);
|
||||
|
||||
@confirmationSpies = jasmine.createSpyObj('Notification.Confirmation', ["constructor", "show"])
|
||||
@confirmationSpies.constructor.and.returnValue(@confirmationSpies)
|
||||
@confirmationSpies.show.and.returnValue(@confirmationSpies)
|
||||
this.confirmationSpies = jasmine.createSpyObj('Notification.Confirmation', ["constructor", "show"]);
|
||||
this.confirmationSpies.constructor.and.returnValue(this.confirmationSpies);
|
||||
this.confirmationSpies.show.and.returnValue(this.confirmationSpies);
|
||||
|
||||
@savingSpies = jasmine.createSpyObj('Notification.Mini', ["constructor", "show", "hide"])
|
||||
@savingSpies.constructor.and.returnValue(@savingSpies)
|
||||
@savingSpies.show.and.returnValue(@savingSpies)
|
||||
this.savingSpies = jasmine.createSpyObj('Notification.Mini', ["constructor", "show", "hide"]);
|
||||
this.savingSpies.constructor.and.returnValue(this.savingSpies);
|
||||
this.savingSpies.show.and.returnValue(this.savingSpies);
|
||||
|
||||
@injector = new Squire()
|
||||
@injector.mock("common/js/components/views/feedback_prompt", {
|
||||
"Warning": @promptSpies.constructor
|
||||
})
|
||||
@injector.mock("common/js/components/views/feedback_notification", {
|
||||
"Confirmation": @confirmationSpies.constructor,
|
||||
"Mini": @savingSpies.constructor
|
||||
})
|
||||
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
|
||||
});
|
||||
|
||||
@injector.require ["js/models/asset", "js/collections/asset", "js/views/asset"],
|
||||
(AssetModel, AssetCollection, AssetView) =>
|
||||
@model = new AssetModel
|
||||
display_name: "test asset"
|
||||
url: 'actual_asset_url'
|
||||
portable_url: 'portable_url'
|
||||
date_added: 'date'
|
||||
thumbnail: null
|
||||
return 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(@model, "destroy").and.callThrough()
|
||||
spyOn(@model, "save").and.callThrough()
|
||||
});
|
||||
spyOn(this.model, "destroy").and.callThrough();
|
||||
spyOn(this.model, "save").and.callThrough();
|
||||
|
||||
@collection = new AssetCollection([@model])
|
||||
@collection.url = "assets-url"
|
||||
@createAssetView = (test) =>
|
||||
view = new AssetView({model: @model})
|
||||
requests = if test then AjaxHelpers["requests"](test) else null
|
||||
return {view: view, requests: requests}
|
||||
done()
|
||||
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 ->
|
||||
@injector.clean()
|
||||
@injector.remove()
|
||||
afterEach(function() {
|
||||
this.injector.clean();
|
||||
return this.injector.remove();
|
||||
});
|
||||
|
||||
describe "Basic", ->
|
||||
it "should render properly", ->
|
||||
{view: @view, requests: requests} = @createAssetView()
|
||||
@view.render()
|
||||
expect(@view.$el).toContainText("test asset")
|
||||
describe("Basic", function() {
|
||||
it("should render properly", function() {
|
||||
let requests;
|
||||
({view: this.view, requests} = this.createAssetView());
|
||||
this.view.render();
|
||||
return expect(this.view.$el).toContainText("test asset");
|
||||
});
|
||||
|
||||
it "should pop a delete confirmation when the delete button is clicked", ->
|
||||
{view: @view, requests: requests} = @createAssetView()
|
||||
@view.render().$(".remove-asset-button").click()
|
||||
expect(@promptSpies.constructor).toHaveBeenCalled()
|
||||
ctorOptions = @promptSpies.constructor.calls.mostRecent().args[0]
|
||||
expect(ctorOptions.title).toMatch('Delete File Confirmation')
|
||||
# hasn't actually been removed
|
||||
expect(@model.destroy).not.toHaveBeenCalled()
|
||||
expect(@collection).toContain(@model)
|
||||
return 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();
|
||||
return expect(this.collection).toContain(this.model);
|
||||
});
|
||||
});
|
||||
|
||||
describe "AJAX", ->
|
||||
it "should destroy itself on confirmation", ->
|
||||
{view: @view, requests: requests} = @createAssetView(this)
|
||||
return describe("AJAX", function() {
|
||||
it("should destroy itself on confirmation", function() {
|
||||
let requests;
|
||||
({view: this.view, requests} = this.createAssetView(this));
|
||||
|
||||
@view.render().$(".remove-asset-button").click()
|
||||
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
|
||||
expect(@model.destroy).toHaveBeenCalled()
|
||||
expect(requests.length).toEqual(1)
|
||||
expect(@confirmationSpies.constructor).not.toHaveBeenCalled()
|
||||
expect(@collection.contains(@model)).toBeTruthy()
|
||||
# return a success response
|
||||
requests[0].respond(204)
|
||||
expect(@confirmationSpies.constructor).toHaveBeenCalled()
|
||||
expect(@confirmationSpies.show).toHaveBeenCalled()
|
||||
savingOptions = @confirmationSpies.constructor.calls.mostRecent().args[0]
|
||||
expect(savingOptions.title).toMatch("Your file has been deleted.")
|
||||
expect(@collection.contains(@model)).toBeFalsy()
|
||||
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.");
|
||||
return expect(this.collection.contains(this.model)).toBeFalsy();
|
||||
});
|
||||
|
||||
it "should not destroy itself if server errors", ->
|
||||
{view: @view, requests: requests} = @createAssetView(this)
|
||||
it("should not destroy itself if server errors", function() {
|
||||
let requests;
|
||||
({view: this.view, requests} = this.createAssetView(this));
|
||||
|
||||
@view.render().$(".remove-asset-button").click()
|
||||
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
|
||||
expect(@model.destroy).toHaveBeenCalled()
|
||||
# return an error response
|
||||
requests[0].respond(404)
|
||||
expect(@confirmationSpies.constructor).not.toHaveBeenCalled()
|
||||
expect(@collection.contains(@model)).toBeTruthy()
|
||||
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();
|
||||
return expect(this.collection.contains(this.model)).toBeTruthy();
|
||||
});
|
||||
|
||||
it "should lock the asset on confirmation", ->
|
||||
{view: @view, requests: requests} = @createAssetView(this)
|
||||
it("should lock the asset on confirmation", function() {
|
||||
let requests;
|
||||
({view: this.view, requests} = this.createAssetView(this));
|
||||
|
||||
@view.render().$(".lock-checkbox").click()
|
||||
# AJAX request has been sent, but not yet returned
|
||||
expect(@model.save).toHaveBeenCalled()
|
||||
expect(requests.length).toEqual(1)
|
||||
expect(@savingSpies.constructor).toHaveBeenCalled()
|
||||
expect(@savingSpies.show).toHaveBeenCalled()
|
||||
savingOptions = @savingSpies.constructor.calls.mostRecent().args[0]
|
||||
expect(savingOptions.title).toMatch("Saving")
|
||||
expect(@model.get("locked")).toBeFalsy()
|
||||
# return a success response
|
||||
requests[0].respond(204)
|
||||
expect(@savingSpies.hide).toHaveBeenCalled()
|
||||
expect(@model.get("locked")).toBeTruthy()
|
||||
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();
|
||||
return expect(this.model.get("locked")).toBeTruthy();
|
||||
});
|
||||
|
||||
it "should not lock the asset if server errors", ->
|
||||
{view: @view, requests: requests} = @createAssetView(this)
|
||||
return it("should not lock the asset if server errors", function() {
|
||||
let requests;
|
||||
({view: this.view, requests} = this.createAssetView(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(@savingSpies.hide).not.toHaveBeenCalled()
|
||||
expect(@model.get("locked")).toBeFalsy()
|
||||
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();
|
||||
return expect(this.model.get("locked")).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe "Assets view", ->
|
||||
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'])
|
||||
window.course_location_analytics = jasmine.createSpy()
|
||||
appendSetFixtures(sandbox({id: "asset_table_body"}))
|
||||
return 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"}));
|
||||
|
||||
@promptSpies = jasmine.createSpyObj('Prompt.Warning', ["constructor", "show", "hide"])
|
||||
@promptSpies.constructor.and.returnValue(@promptSpies)
|
||||
@promptSpies.show.and.returnValue(@promptSpies)
|
||||
this.promptSpies = jasmine.createSpyObj('Prompt.Warning', ["constructor", "show", "hide"]);
|
||||
this.promptSpies.constructor.and.returnValue(this.promptSpies);
|
||||
this.promptSpies.show.and.returnValue(this.promptSpies);
|
||||
|
||||
@injector = new Squire()
|
||||
@injector.mock("common/js/components/views/feedback_prompt", {
|
||||
"Warning": @promptSpies.constructor
|
||||
})
|
||||
this.injector = new Squire();
|
||||
this.injector.mock("common/js/components/views/feedback_prompt", {
|
||||
"Warning": this.promptSpies.constructor
|
||||
});
|
||||
|
||||
@mockAsset1 = {
|
||||
display_name: "test asset 1"
|
||||
url: 'actual_asset_url_1'
|
||||
portable_url: 'portable_url_1'
|
||||
date_added: 'date_1'
|
||||
thumbnail: null
|
||||
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'
|
||||
}
|
||||
@mockAsset2 = {
|
||||
display_name: "test asset 2"
|
||||
url: 'actual_asset_url_2'
|
||||
portable_url: 'portable_url_2'
|
||||
date_added: 'date_2'
|
||||
thumbnail: null
|
||||
};
|
||||
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'
|
||||
}
|
||||
@mockAssetsResponse = {
|
||||
assets: [ @mockAsset1, @mockAsset2 ],
|
||||
};
|
||||
this.mockAssetsResponse = {
|
||||
assets: [ this.mockAsset1, this.mockAsset2 ],
|
||||
start: 0,
|
||||
end: 1,
|
||||
page: 0,
|
||||
pageSize: 5,
|
||||
totalCount: 2
|
||||
}
|
||||
};
|
||||
|
||||
@injector.require ["js/models/asset", "js/collections/asset", "js/views/assets"],
|
||||
(AssetModel, AssetCollection, AssetsView) =>
|
||||
@AssetModel = AssetModel
|
||||
@collection = new AssetCollection();
|
||||
@collection.url = "assets-url"
|
||||
@createAssetsView = (test) =>
|
||||
requests = AjaxHelpers.requests(test)
|
||||
view = new AssetsView
|
||||
collection: @collection
|
||||
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: view, requests: requests}
|
||||
done()
|
||||
});
|
||||
view.render();
|
||||
return {view, requests};
|
||||
};
|
||||
return done();
|
||||
});
|
||||
|
||||
$.ajax()
|
||||
return $.ajax();
|
||||
});
|
||||
|
||||
afterEach ->
|
||||
delete window.analytics
|
||||
delete window.course_location_analytics
|
||||
afterEach(function() {
|
||||
delete window.analytics;
|
||||
delete window.course_location_analytics;
|
||||
|
||||
@injector.clean()
|
||||
@injector.remove()
|
||||
this.injector.clean();
|
||||
return this.injector.remove();
|
||||
});
|
||||
|
||||
addMockAsset = (requests) ->
|
||||
model = new @AssetModel
|
||||
display_name: "new asset"
|
||||
url: 'new_actual_asset_url'
|
||||
portable_url: 'portable_url'
|
||||
date_added: 'date'
|
||||
thumbnail: null
|
||||
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'
|
||||
@view.addAsset(model)
|
||||
AjaxHelpers.respondWithJson(requests,
|
||||
});
|
||||
this.view.addAsset(model);
|
||||
return AjaxHelpers.respondWithJson(requests,
|
||||
{
|
||||
assets: [
|
||||
@mockAsset1, @mockAsset2,
|
||||
this.mockAsset1, this.mockAsset2,
|
||||
{
|
||||
display_name: "new asset"
|
||||
url: 'new_actual_asset_url'
|
||||
portable_url: 'portable_url'
|
||||
date_added: 'date'
|
||||
thumbnail: null
|
||||
display_name: "new asset",
|
||||
url: 'new_actual_asset_url',
|
||||
portable_url: 'portable_url',
|
||||
date_added: 'date',
|
||||
thumbnail: null,
|
||||
id: 'idx'
|
||||
}
|
||||
],
|
||||
@@ -224,146 +255,179 @@ define ["jquery", "edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers", "squire"]
|
||||
page: 0,
|
||||
pageSize: 5,
|
||||
totalCount: 3
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
describe "Basic", ->
|
||||
# Separate setup method to work-around mis-parenting of beforeEach methods
|
||||
setup = (requests) ->
|
||||
@view.pagingView.setPage(1)
|
||||
AjaxHelpers.respondWithJson(requests, @mockAssetsResponse)
|
||||
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 = ->
|
||||
return ''
|
||||
$.fn.fileupload = () => '';
|
||||
|
||||
clickEvent = (html_selector) ->
|
||||
$(html_selector).click()
|
||||
const clickEvent = html_selector => $(html_selector).click();
|
||||
|
||||
it "should show upload modal on clicking upload asset button", ->
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
spyOn(@view, "showUploadModal")
|
||||
setup.call(this, requests)
|
||||
expect(@view.showUploadModal).not.toHaveBeenCalled()
|
||||
@view.showUploadModal(clickEvent(".upload-button"))
|
||||
expect(@view.showUploadModal).toHaveBeenCalled()
|
||||
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"));
|
||||
return expect(this.view.showUploadModal).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it "should show file selection menu on choose file button", ->
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
spyOn(@view, "showFileSelectionMenu")
|
||||
setup.call(this, requests)
|
||||
expect(@view.showFileSelectionMenu).not.toHaveBeenCalled()
|
||||
@view.showFileSelectionMenu(clickEvent(".choose-file-button"))
|
||||
expect(@view.showFileSelectionMenu).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"));
|
||||
return expect(this.view.showFileSelectionMenu).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it "should hide upload modal on clicking close button", ->
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
spyOn(@view, "hideModal")
|
||||
setup.call(this, requests)
|
||||
expect(@view.hideModal).not.toHaveBeenCalled()
|
||||
@view.hideModal(clickEvent(".close-button"))
|
||||
expect(@view.hideModal).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"));
|
||||
return expect(this.view.hideModal).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it "should show a status indicator while loading", ->
|
||||
{view: @view, requests: requests} = @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 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);
|
||||
return expect($('.ui-loading').is(':visible')).toBe(false);
|
||||
});
|
||||
|
||||
it "should hide the status indicator if an error occurs while loading", ->
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
appendSetFixtures('<div class="ui-loading"/>')
|
||||
expect($('.ui-loading').is(':visible')).toBe(true)
|
||||
@view.pagingView.setPage(1)
|
||||
AjaxHelpers.respondWithError(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);
|
||||
return expect($('.ui-loading').is(':visible')).toBe(false);
|
||||
});
|
||||
|
||||
it "should render both assets", ->
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
setup.call(this, requests)
|
||||
expect(@view.$el).toContainText("test asset 1")
|
||||
expect(@view.$el).toContainText("test asset 2")
|
||||
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");
|
||||
return expect(this.view.$el).toContainText("test asset 2");
|
||||
});
|
||||
|
||||
it "should remove the deleted asset from the view", ->
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
AjaxHelpers.respondWithJson(requests, @mockAssetsResponse)
|
||||
setup.call(this, requests)
|
||||
# Delete the 2nd asset with success from server.
|
||||
@view.$(".remove-asset-button")[1].click()
|
||||
@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")
|
||||
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");
|
||||
return expect(this.view.$el).not.toContainText("test asset 2");
|
||||
});
|
||||
|
||||
it "does not remove asset if deletion failed", ->
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
setup.call(this, requests)
|
||||
# Delete the 2nd asset, but mimic a failure from the server.
|
||||
@view.$(".remove-asset-button")[1].click()
|
||||
@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")
|
||||
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");
|
||||
return expect(this.view.$el).toContainText("test asset 2");
|
||||
});
|
||||
|
||||
it "adds an asset if asset does not already exist", ->
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
setup.call(this, requests)
|
||||
addMockAsset.call(this, requests)
|
||||
expect(@view.$el).toContainText("new asset")
|
||||
expect(@collection.models.length).toBe(3)
|
||||
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");
|
||||
return expect(this.collection.models.length).toBe(3);
|
||||
});
|
||||
|
||||
it "does not add an asset if asset already exists", ->
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
setup.call(this, requests)
|
||||
spyOn(@collection, "add").and.callThrough()
|
||||
model = @collection.models[1]
|
||||
@view.addAsset(model)
|
||||
expect(@collection.add).not.toHaveBeenCalled()
|
||||
return 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);
|
||||
return expect(this.collection.add).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe "Sorting", ->
|
||||
# Separate setup method to work-around mis-parenting of beforeEach methods
|
||||
setup = (requests) ->
|
||||
@view.pagingView.setPage(1)
|
||||
AjaxHelpers.respondWithJson(requests, @mockAssetsResponse)
|
||||
return 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", ->
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
setup.call(this, requests)
|
||||
expect(@view.pagingView.sortDisplayName()).toBe("Date Added")
|
||||
expect(@view.collection.sortDirection).toBe("desc")
|
||||
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");
|
||||
return expect(this.view.collection.sortDirection).toBe("desc");
|
||||
});
|
||||
|
||||
it "should toggle the sort order when clicking on the currently sorted column", ->
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
setup.call(this, requests)
|
||||
expect(@view.pagingView.sortDisplayName()).toBe("Date Added")
|
||||
expect(@view.collection.sortDirection).toBe("desc")
|
||||
@view.$("#js-asset-date-col").click()
|
||||
AjaxHelpers.respondWithJson(requests, @mockAssetsResponse)
|
||||
expect(@view.pagingView.sortDisplayName()).toBe("Date Added")
|
||||
expect(@view.collection.sortDirection).toBe("asc")
|
||||
@view.$("#js-asset-date-col").click()
|
||||
AjaxHelpers.respondWithJson(requests, @mockAssetsResponse)
|
||||
expect(@view.pagingView.sortDisplayName()).toBe("Date Added")
|
||||
expect(@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");
|
||||
return expect(this.view.collection.sortDirection).toBe("desc");
|
||||
});
|
||||
|
||||
it "should switch the sort order when clicking on a different column", ->
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
setup.call(this, requests)
|
||||
@view.$("#js-asset-name-col").click()
|
||||
AjaxHelpers.respondWithJson(requests, @mockAssetsResponse)
|
||||
expect(@view.pagingView.sortDisplayName()).toBe("Name")
|
||||
expect(@view.collection.sortDirection).toBe("asc")
|
||||
@view.$("#js-asset-name-col").click()
|
||||
AjaxHelpers.respondWithJson(requests, @mockAssetsResponse)
|
||||
expect(@view.pagingView.sortDisplayName()).toBe("Name")
|
||||
expect(@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");
|
||||
return expect(this.view.collection.sortDirection).toBe("desc");
|
||||
});
|
||||
|
||||
it "should switch sort to most recent date added when a new asset is added", ->
|
||||
{view: @view, requests: requests} = @createAssetsView(this)
|
||||
setup.call(this, requests)
|
||||
@view.$("#js-asset-name-col").click()
|
||||
AjaxHelpers.respondWithJson(requests, @mockAssetsResponse)
|
||||
addMockAsset.call(this, requests)
|
||||
AjaxHelpers.respondWithJson(requests, @mockAssetsResponse)
|
||||
expect(@view.pagingView.sortDisplayName()).toBe("Date Added")
|
||||
expect(@view.collection.sortDirection).toBe("desc")
|
||||
return 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");
|
||||
return expect(this.view.collection.sortDirection).toBe("desc");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,298 +1,339 @@
|
||||
define ["js/views/course_info_handout", "js/views/course_info_update", "js/models/module_info",
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
define(["js/views/course_info_handout", "js/views/course_info_update", "js/models/module_info",
|
||||
"js/collections/course_update", "edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers"],
|
||||
(CourseInfoHandoutsView, CourseInfoUpdateView, ModuleInfo, CourseUpdateCollection, AjaxHelpers) ->
|
||||
(CourseInfoHandoutsView, CourseInfoUpdateView, ModuleInfo, CourseUpdateCollection, AjaxHelpers) =>
|
||||
|
||||
describe "Course Updates and Handouts", ->
|
||||
courseInfoPage = """
|
||||
<div class="course-info-wrapper">
|
||||
<div class="main-column window">
|
||||
<article class="course-updates" id="course-update-view">
|
||||
<ol class="update-list" id="course-update-list"></ol>
|
||||
</article>
|
||||
</div>
|
||||
<div class="sidebar window course-handouts" id="course-handouts-view"></div>
|
||||
</div>
|
||||
<div class="modal-cover"></div>
|
||||
"""
|
||||
describe("Course Updates and Handouts", function() {
|
||||
const courseInfoPage = `\
|
||||
<div class="course-info-wrapper">
|
||||
<div class="main-column window">
|
||||
<article class="course-updates" id="course-update-view">
|
||||
<ol class="update-list" id="course-update-list"></ol>
|
||||
</article>
|
||||
</div>
|
||||
<div class="sidebar window course-handouts" id="course-handouts-view"></div>
|
||||
</div>
|
||||
<div class="modal-cover"></div>\
|
||||
`;
|
||||
|
||||
beforeEach ->
|
||||
window.analytics = jasmine.createSpyObj('analytics', ['track'])
|
||||
window.course_location_analytics = jasmine.createSpy()
|
||||
beforeEach(function() {
|
||||
window.analytics = jasmine.createSpyObj('analytics', ['track']);
|
||||
return window.course_location_analytics = jasmine.createSpy();
|
||||
});
|
||||
|
||||
afterEach ->
|
||||
delete window.analytics
|
||||
delete window.course_location_analytics
|
||||
afterEach(function() {
|
||||
delete window.analytics;
|
||||
return delete window.course_location_analytics;
|
||||
});
|
||||
|
||||
describe "Course Updates without Push notification", ->
|
||||
courseInfoTemplate = readFixtures('course_info_update.underscore')
|
||||
describe("Course Updates without Push notification", function() {
|
||||
const courseInfoTemplate = readFixtures('course_info_update.underscore');
|
||||
|
||||
beforeEach ->
|
||||
setFixtures($("<script>", {id: "course_info_update-tpl", type: "text/template"}).text(courseInfoTemplate))
|
||||
appendSetFixtures courseInfoPage
|
||||
beforeEach(function() {
|
||||
let cancelEditingUpdate;
|
||||
setFixtures($("<script>", {id: "course_info_update-tpl", type: "text/template"}).text(courseInfoTemplate));
|
||||
appendSetFixtures(courseInfoPage);
|
||||
|
||||
@collection = new CourseUpdateCollection()
|
||||
@collection.url = 'course_info_update/'
|
||||
@courseInfoEdit = new CourseInfoUpdateView({
|
||||
this.collection = new CourseUpdateCollection();
|
||||
this.collection.url = 'course_info_update/';
|
||||
this.courseInfoEdit = new CourseInfoUpdateView({
|
||||
el: $('.course-updates'),
|
||||
collection: @collection,
|
||||
collection: this.collection,
|
||||
base_asset_url : 'base-asset-url/'
|
||||
})
|
||||
});
|
||||
|
||||
@courseInfoEdit.render()
|
||||
this.courseInfoEdit.render();
|
||||
|
||||
@event = {
|
||||
preventDefault : () -> 'no op'
|
||||
}
|
||||
this.event = {
|
||||
preventDefault() { return 'no op'; }
|
||||
};
|
||||
|
||||
@createNewUpdate = (text) ->
|
||||
# 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').and.returnValue(text)
|
||||
@courseInfoEdit.$el.find('.save-button').click()
|
||||
this.createNewUpdate = function(text) {
|
||||
// Edit button is not in the template under test (it is in parent HTML).
|
||||
// Therefore call onNew directly.
|
||||
this.courseInfoEdit.onNew(this.event);
|
||||
spyOn(this.courseInfoEdit.$codeMirror, 'getValue').and.returnValue(text);
|
||||
return this.courseInfoEdit.$el.find('.save-button').click();
|
||||
};
|
||||
|
||||
@cancelNewCourseInfo = (useCancelButton) ->
|
||||
@courseInfoEdit.onNew(@event)
|
||||
spyOn(@courseInfoEdit.$modalCover, 'hide').and.callThrough()
|
||||
this.cancelNewCourseInfo = function(useCancelButton) {
|
||||
this.courseInfoEdit.onNew(this.event);
|
||||
spyOn(this.courseInfoEdit.$modalCover, 'hide').and.callThrough();
|
||||
|
||||
spyOn(@courseInfoEdit.$codeMirror, 'getValue').and.returnValue('unsaved changes')
|
||||
model = @collection.at(0)
|
||||
spyOn(model, "save").and.callThrough()
|
||||
spyOn(this.courseInfoEdit.$codeMirror, 'getValue').and.returnValue('unsaved changes');
|
||||
const model = this.collection.at(0);
|
||||
spyOn(model, "save").and.callThrough();
|
||||
|
||||
cancelEditingUpdate(@courseInfoEdit, @courseInfoEdit.$modalCover, useCancelButton)
|
||||
cancelEditingUpdate(this.courseInfoEdit, this.courseInfoEdit.$modalCover, useCancelButton);
|
||||
|
||||
expect(@courseInfoEdit.$modalCover.hide).toHaveBeenCalled()
|
||||
expect(model.save).not.toHaveBeenCalled()
|
||||
previewContents = @courseInfoEdit.$el.find('.update-contents').html()
|
||||
expect(previewContents).not.toEqual('unsaved changes')
|
||||
expect(this.courseInfoEdit.$modalCover.hide).toHaveBeenCalled();
|
||||
expect(model.save).not.toHaveBeenCalled();
|
||||
const previewContents = this.courseInfoEdit.$el.find('.update-contents').html();
|
||||
return expect(previewContents).not.toEqual('unsaved changes');
|
||||
};
|
||||
|
||||
@doNotCloseNewCourseInfo = () ->
|
||||
@courseInfoEdit.onNew(@event)
|
||||
spyOn(@courseInfoEdit.$modalCover, 'hide').and.callThrough()
|
||||
this.doNotCloseNewCourseInfo = function() {
|
||||
this.courseInfoEdit.onNew(this.event);
|
||||
spyOn(this.courseInfoEdit.$modalCover, 'hide').and.callThrough();
|
||||
|
||||
spyOn(@courseInfoEdit.$codeMirror, 'getValue').and.returnValue('unsaved changes')
|
||||
model = @collection.at(0)
|
||||
spyOn(model, "save").and.callThrough()
|
||||
spyOn(this.courseInfoEdit.$codeMirror, 'getValue').and.returnValue('unsaved changes');
|
||||
const model = this.collection.at(0);
|
||||
spyOn(model, "save").and.callThrough();
|
||||
|
||||
cancelEditingUpdate(@courseInfoEdit, @courseInfoEdit.$modalCover, false)
|
||||
cancelEditingUpdate(this.courseInfoEdit, this.courseInfoEdit.$modalCover, false);
|
||||
|
||||
expect(model.save).not.toHaveBeenCalled()
|
||||
expect(@courseInfoEdit.$modalCover.hide).not.toHaveBeenCalled()
|
||||
expect(model.save).not.toHaveBeenCalled();
|
||||
return expect(this.courseInfoEdit.$modalCover.hide).not.toHaveBeenCalled();
|
||||
};
|
||||
|
||||
@cancelExistingCourseInfo = (useCancelButton) ->
|
||||
@createNewUpdate('existing update')
|
||||
@courseInfoEdit.$el.find('.edit-button').click()
|
||||
spyOn(@courseInfoEdit.$modalCover, 'hide').and.callThrough()
|
||||
this.cancelExistingCourseInfo = function(useCancelButton) {
|
||||
this.createNewUpdate('existing update');
|
||||
this.courseInfoEdit.$el.find('.edit-button').click();
|
||||
spyOn(this.courseInfoEdit.$modalCover, 'hide').and.callThrough();
|
||||
|
||||
spyOn(@courseInfoEdit.$codeMirror, 'getValue').and.returnValue('modification')
|
||||
model = @collection.at(0)
|
||||
spyOn(model, "save").and.callThrough()
|
||||
model.id = "saved_to_server"
|
||||
cancelEditingUpdate(@courseInfoEdit, @courseInfoEdit.$modalCover, useCancelButton)
|
||||
spyOn(this.courseInfoEdit.$codeMirror, 'getValue').and.returnValue('modification');
|
||||
const model = this.collection.at(0);
|
||||
spyOn(model, "save").and.callThrough();
|
||||
model.id = "saved_to_server";
|
||||
cancelEditingUpdate(this.courseInfoEdit, this.courseInfoEdit.$modalCover, useCancelButton);
|
||||
|
||||
expect(@courseInfoEdit.$modalCover.hide).toHaveBeenCalled()
|
||||
expect(model.save).not.toHaveBeenCalled()
|
||||
previewContents = @courseInfoEdit.$el.find('.update-contents').html()
|
||||
expect(previewContents).toEqual('existing update')
|
||||
expect(this.courseInfoEdit.$modalCover.hide).toHaveBeenCalled();
|
||||
expect(model.save).not.toHaveBeenCalled();
|
||||
const previewContents = this.courseInfoEdit.$el.find('.update-contents').html();
|
||||
return expect(previewContents).toEqual('existing update');
|
||||
};
|
||||
|
||||
@testInvalidDateValue = (value) ->
|
||||
@courseInfoEdit.onNew(@event)
|
||||
expect(@courseInfoEdit.$el.find('.save-button').hasClass("is-disabled")).toEqual(false)
|
||||
@courseInfoEdit.$el.find('input.date').val(value).trigger("change")
|
||||
expect(@courseInfoEdit.$el.find('.save-button').hasClass("is-disabled")).toEqual(true)
|
||||
@courseInfoEdit.$el.find('input.date').val("01/01/16").trigger("change")
|
||||
expect(@courseInfoEdit.$el.find('.save-button').hasClass("is-disabled")).toEqual(false)
|
||||
this.testInvalidDateValue = function(value) {
|
||||
this.courseInfoEdit.onNew(this.event);
|
||||
expect(this.courseInfoEdit.$el.find('.save-button').hasClass("is-disabled")).toEqual(false);
|
||||
this.courseInfoEdit.$el.find('input.date').val(value).trigger("change");
|
||||
expect(this.courseInfoEdit.$el.find('.save-button').hasClass("is-disabled")).toEqual(true);
|
||||
this.courseInfoEdit.$el.find('input.date').val("01/01/16").trigger("change");
|
||||
return expect(this.courseInfoEdit.$el.find('.save-button').hasClass("is-disabled")).toEqual(false);
|
||||
};
|
||||
|
||||
cancelEditingUpdate = (update, modalCover, useCancelButton) ->
|
||||
if useCancelButton
|
||||
update.$el.find('.cancel-button').click()
|
||||
else
|
||||
modalCover.click()
|
||||
return cancelEditingUpdate = function(update, modalCover, useCancelButton) {
|
||||
if (useCancelButton) {
|
||||
return update.$el.find('.cancel-button').click();
|
||||
} else {
|
||||
return modalCover.click();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
it "does send expected data on save", ->
|
||||
requests = AjaxHelpers["requests"](this)
|
||||
it("does send expected data on save", function() {
|
||||
const requests = AjaxHelpers["requests"](this);
|
||||
|
||||
# Create a new update, verifying that the model is created
|
||||
# in the collection and save is called.
|
||||
expect(@collection.isEmpty()).toBeTruthy()
|
||||
@courseInfoEdit.onNew(@event)
|
||||
expect(@collection.length).toEqual(1)
|
||||
model = @collection.at(0)
|
||||
spyOn(model, "save").and.callThrough()
|
||||
spyOn(@courseInfoEdit.$codeMirror, 'getValue').and.returnValue('/static/image.jpg')
|
||||
// Create a new update, verifying that the model is created
|
||||
// in the collection and save is called.
|
||||
expect(this.collection.isEmpty()).toBeTruthy();
|
||||
this.courseInfoEdit.onNew(this.event);
|
||||
expect(this.collection.length).toEqual(1);
|
||||
const model = this.collection.at(0);
|
||||
spyOn(model, "save").and.callThrough();
|
||||
spyOn(this.courseInfoEdit.$codeMirror, 'getValue').and.returnValue('/static/image.jpg');
|
||||
|
||||
# Click the "Save button."
|
||||
@courseInfoEdit.$el.find('.save-button').click()
|
||||
expect(model.save).toHaveBeenCalled()
|
||||
// Click the "Save button."
|
||||
this.courseInfoEdit.$el.find('.save-button').click();
|
||||
expect(model.save).toHaveBeenCalled();
|
||||
|
||||
# Verify push_notification_selected is set to false.
|
||||
requestSent = JSON.parse(requests[requests.length - 1].requestBody)
|
||||
expect(requestSent.push_notification_selected).toEqual(false)
|
||||
// Verify push_notification_selected is set to false.
|
||||
const requestSent = JSON.parse(requests[requests.length - 1].requestBody);
|
||||
expect(requestSent.push_notification_selected).toEqual(false);
|
||||
|
||||
# Verify the link is not rewritten when saved.
|
||||
expect(requestSent.content).toEqual('/static/image.jpg')
|
||||
// Verify the link is not rewritten when saved.
|
||||
expect(requestSent.content).toEqual('/static/image.jpg');
|
||||
|
||||
# Verify that analytics are sent
|
||||
expect(window.analytics.track).toHaveBeenCalled()
|
||||
// Verify that analytics are sent
|
||||
return expect(window.analytics.track).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it "does rewrite links for preview", ->
|
||||
# Create a new update.
|
||||
@createNewUpdate('/static/image.jpg')
|
||||
it("does rewrite links for preview", function() {
|
||||
// Create a new update.
|
||||
this.createNewUpdate('/static/image.jpg');
|
||||
|
||||
# Verify the link is rewritten for preview purposes.
|
||||
previewContents = @courseInfoEdit.$el.find('.update-contents').html()
|
||||
expect(previewContents).toEqual('base-asset-url/image.jpg')
|
||||
// Verify the link is rewritten for preview purposes.
|
||||
const previewContents = this.courseInfoEdit.$el.find('.update-contents').html();
|
||||
return expect(previewContents).toEqual('base-asset-url/image.jpg');
|
||||
});
|
||||
|
||||
it "shows static links in edit mode", ->
|
||||
@createNewUpdate('/static/image.jpg')
|
||||
it("shows static links in edit mode", function() {
|
||||
this.createNewUpdate('/static/image.jpg');
|
||||
|
||||
# Click edit and verify CodeMirror contents.
|
||||
@courseInfoEdit.$el.find('.edit-button').click()
|
||||
expect(@courseInfoEdit.$codeMirror.getValue()).toEqual('/static/image.jpg')
|
||||
// Click edit and verify CodeMirror contents.
|
||||
this.courseInfoEdit.$el.find('.edit-button').click();
|
||||
return expect(this.courseInfoEdit.$codeMirror.getValue()).toEqual('/static/image.jpg');
|
||||
});
|
||||
|
||||
it "removes newly created course info on cancel", ->
|
||||
@cancelNewCourseInfo(true)
|
||||
it("removes newly created course info on cancel", function() {
|
||||
return this.cancelNewCourseInfo(true);
|
||||
});
|
||||
|
||||
it "do not close new course info on click outside modal", ->
|
||||
@doNotCloseNewCourseInfo()
|
||||
it("do not close new course info on click outside modal", function() {
|
||||
return this.doNotCloseNewCourseInfo();
|
||||
});
|
||||
|
||||
it "does not remove existing course info on cancel", ->
|
||||
@cancelExistingCourseInfo(true)
|
||||
it("does not remove existing course info on cancel", function() {
|
||||
return this.cancelExistingCourseInfo(true);
|
||||
});
|
||||
|
||||
it "does not remove existing course info on click outside modal", ->
|
||||
@cancelExistingCourseInfo(false)
|
||||
it("does not remove existing course info on click outside modal", function() {
|
||||
return this.cancelExistingCourseInfo(false);
|
||||
});
|
||||
|
||||
it "does not allow updates to be saved with an invalid date", ->
|
||||
@testInvalidDateValue("Marchtober 40, 2048")
|
||||
it("does not allow updates to be saved with an invalid date", function() {
|
||||
return this.testInvalidDateValue("Marchtober 40, 2048");
|
||||
});
|
||||
|
||||
it "does not allow updates to be saved with a blank date", ->
|
||||
@testInvalidDateValue("")
|
||||
return it("does not allow updates to be saved with a blank date", function() {
|
||||
return this.testInvalidDateValue("");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe "Course Updates WITH Push notification", ->
|
||||
courseInfoTemplate = readFixtures('course_info_update.underscore')
|
||||
describe("Course Updates WITH Push notification", function() {
|
||||
const courseInfoTemplate = readFixtures('course_info_update.underscore');
|
||||
|
||||
beforeEach ->
|
||||
setFixtures($("<script>", {id: "course_info_update-tpl", type: "text/template"}).text(courseInfoTemplate))
|
||||
appendSetFixtures courseInfoPage
|
||||
@collection = new CourseUpdateCollection()
|
||||
@collection.url = 'course_info_update/'
|
||||
@courseInfoEdit = new CourseInfoUpdateView({
|
||||
beforeEach(function() {
|
||||
setFixtures($("<script>", {id: "course_info_update-tpl", type: "text/template"}).text(courseInfoTemplate));
|
||||
appendSetFixtures(courseInfoPage);
|
||||
this.collection = new CourseUpdateCollection();
|
||||
this.collection.url = 'course_info_update/';
|
||||
this.courseInfoEdit = new CourseInfoUpdateView({
|
||||
el: $('.course-updates'),
|
||||
collection: @collection,
|
||||
collection: this.collection,
|
||||
base_asset_url : 'base-asset-url/',
|
||||
push_notification_enabled : true
|
||||
})
|
||||
@courseInfoEdit.render()
|
||||
@event = {preventDefault : () -> 'no op'}
|
||||
@courseInfoEdit.onNew(@event)
|
||||
});
|
||||
this.courseInfoEdit.render();
|
||||
this.event = {preventDefault() { return 'no op'; }};
|
||||
return this.courseInfoEdit.onNew(this.event);
|
||||
});
|
||||
|
||||
it "shows push notification checkbox as selected by default", ->
|
||||
expect(@courseInfoEdit.$el.find('.toggle-checkbox')).toBeChecked()
|
||||
it("shows push notification checkbox as selected by default", function() {
|
||||
return expect(this.courseInfoEdit.$el.find('.toggle-checkbox')).toBeChecked();
|
||||
});
|
||||
|
||||
it "sends correct default value for push_notification_selected", ->
|
||||
requests = AjaxHelpers.requests(this);
|
||||
@courseInfoEdit.$el.find('.save-button').click()
|
||||
requestSent = JSON.parse(requests[requests.length - 1].requestBody)
|
||||
expect(requestSent.push_notification_selected).toEqual(true)
|
||||
it("sends correct default value for push_notification_selected", function() {
|
||||
const requests = AjaxHelpers.requests(this);
|
||||
this.courseInfoEdit.$el.find('.save-button').click();
|
||||
const requestSent = JSON.parse(requests[requests.length - 1].requestBody);
|
||||
expect(requestSent.push_notification_selected).toEqual(true);
|
||||
|
||||
# Check that analytics send push_notification info
|
||||
analytics_payload = window.analytics.track.calls.first().args[1]
|
||||
expect(analytics_payload).toEqual(jasmine.objectContaining({'push_notification_selected': true}))
|
||||
// Check that analytics send push_notification info
|
||||
const analytics_payload = window.analytics.track.calls.first().args[1];
|
||||
return expect(analytics_payload).toEqual(jasmine.objectContaining({'push_notification_selected': true}));
|
||||
});
|
||||
|
||||
it "sends correct value for push_notification_selected when it is unselected", ->
|
||||
requests = AjaxHelpers.requests(this);
|
||||
# unselect push notification
|
||||
@courseInfoEdit.$el.find('.toggle-checkbox').attr('checked', false);
|
||||
@courseInfoEdit.$el.find('.save-button').click()
|
||||
requestSent = JSON.parse(requests[requests.length - 1].requestBody)
|
||||
expect(requestSent.push_notification_selected).toEqual(false)
|
||||
return it("sends correct value for push_notification_selected when it is unselected", function() {
|
||||
const requests = AjaxHelpers.requests(this);
|
||||
// unselect push notification
|
||||
this.courseInfoEdit.$el.find('.toggle-checkbox').attr('checked', false);
|
||||
this.courseInfoEdit.$el.find('.save-button').click();
|
||||
const requestSent = JSON.parse(requests[requests.length - 1].requestBody);
|
||||
expect(requestSent.push_notification_selected).toEqual(false);
|
||||
|
||||
# Check that analytics send push_notification info
|
||||
analytics_payload = window.analytics.track.calls.first().args[1]
|
||||
expect(analytics_payload).toEqual(jasmine.objectContaining({'push_notification_selected': false}))
|
||||
// Check that analytics send push_notification info
|
||||
const analytics_payload = window.analytics.track.calls.first().args[1];
|
||||
return expect(analytics_payload).toEqual(jasmine.objectContaining({'push_notification_selected': false}));
|
||||
});
|
||||
});
|
||||
|
||||
describe "Course Handouts", ->
|
||||
handoutsTemplate = readFixtures('course_info_handouts.underscore')
|
||||
return describe("Course Handouts", function() {
|
||||
const handoutsTemplate = readFixtures('course_info_handouts.underscore');
|
||||
|
||||
beforeEach ->
|
||||
setFixtures($("<script>", {id: "course_info_handouts-tpl", type: "text/template"}).text(handoutsTemplate))
|
||||
appendSetFixtures courseInfoPage
|
||||
beforeEach(function() {
|
||||
setFixtures($("<script>", {id: "course_info_handouts-tpl", type: "text/template"}).text(handoutsTemplate));
|
||||
appendSetFixtures(courseInfoPage);
|
||||
|
||||
@model = new ModuleInfo({
|
||||
this.model = new ModuleInfo({
|
||||
id: 'handouts-id',
|
||||
data: '/static/fromServer.jpg'
|
||||
})
|
||||
});
|
||||
|
||||
@handoutsEdit = new CourseInfoHandoutsView({
|
||||
this.handoutsEdit = new CourseInfoHandoutsView({
|
||||
el: $('#course-handouts-view'),
|
||||
model: @model,
|
||||
model: this.model,
|
||||
base_asset_url: 'base-asset-url/'
|
||||
});
|
||||
|
||||
@handoutsEdit.render()
|
||||
return this.handoutsEdit.render();
|
||||
});
|
||||
|
||||
it "saves <ol></ol> when content left empty", ->
|
||||
requests = AjaxHelpers["requests"](this)
|
||||
it("saves <ol></ol> when content left empty", function() {
|
||||
const requests = AjaxHelpers["requests"](this);
|
||||
|
||||
# Enter empty string in the handouts section, verifying that the model
|
||||
# is saved with '<ol></ol>' instead of the empty string
|
||||
@handoutsEdit.$el.find('.edit-button').click()
|
||||
spyOn(@handoutsEdit.$codeMirror, 'getValue').and.returnValue('')
|
||||
spyOn(@model, "save").and.callThrough()
|
||||
@handoutsEdit.$el.find('.save-button').click()
|
||||
expect(@model.save).toHaveBeenCalled()
|
||||
// Enter empty string in the handouts section, verifying that the model
|
||||
// is saved with '<ol></ol>' instead of the empty string
|
||||
this.handoutsEdit.$el.find('.edit-button').click();
|
||||
spyOn(this.handoutsEdit.$codeMirror, 'getValue').and.returnValue('');
|
||||
spyOn(this.model, "save").and.callThrough();
|
||||
this.handoutsEdit.$el.find('.save-button').click();
|
||||
expect(this.model.save).toHaveBeenCalled();
|
||||
|
||||
contentSaved = JSON.parse(requests[requests.length - 1].requestBody).data
|
||||
expect(contentSaved).toEqual('<ol></ol>')
|
||||
const contentSaved = JSON.parse(requests[requests.length - 1].requestBody).data;
|
||||
return expect(contentSaved).toEqual('<ol></ol>');
|
||||
});
|
||||
|
||||
it "does not rewrite links on save", ->
|
||||
requests = AjaxHelpers["requests"](this)
|
||||
it("does not rewrite links on save", function() {
|
||||
const requests = AjaxHelpers["requests"](this);
|
||||
|
||||
# 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').and.returnValue('/static/image.jpg')
|
||||
spyOn(@model, "save").and.callThrough()
|
||||
@handoutsEdit.$el.find('.save-button').click()
|
||||
expect(@model.save).toHaveBeenCalled()
|
||||
// Enter something in the handouts section, verifying that the model is saved
|
||||
// when "Save" is clicked.
|
||||
this.handoutsEdit.$el.find('.edit-button').click();
|
||||
spyOn(this.handoutsEdit.$codeMirror, 'getValue').and.returnValue('/static/image.jpg');
|
||||
spyOn(this.model, "save").and.callThrough();
|
||||
this.handoutsEdit.$el.find('.save-button').click();
|
||||
expect(this.model.save).toHaveBeenCalled();
|
||||
|
||||
contentSaved = JSON.parse(requests[requests.length - 1].requestBody).data
|
||||
expect(contentSaved).toEqual('/static/image.jpg')
|
||||
const contentSaved = JSON.parse(requests[requests.length - 1].requestBody).data;
|
||||
return expect(contentSaved).toEqual('/static/image.jpg');
|
||||
});
|
||||
|
||||
it "does rewrite links in initial content", ->
|
||||
expect(@handoutsEdit.$preview.html().trim()).toBe('base-asset-url/fromServer.jpg')
|
||||
it("does rewrite links in initial content", function() {
|
||||
return expect(this.handoutsEdit.$preview.html().trim()).toBe('base-asset-url/fromServer.jpg');
|
||||
});
|
||||
|
||||
it "does rewrite links after edit", ->
|
||||
# Edit handouts and save.
|
||||
@handoutsEdit.$el.find('.edit-button').click()
|
||||
spyOn(@handoutsEdit.$codeMirror, 'getValue').and.returnValue('/static/image.jpg')
|
||||
@handoutsEdit.$el.find('.save-button').click()
|
||||
it("does rewrite links after edit", function() {
|
||||
// Edit handouts and save.
|
||||
this.handoutsEdit.$el.find('.edit-button').click();
|
||||
spyOn(this.handoutsEdit.$codeMirror, 'getValue').and.returnValue('/static/image.jpg');
|
||||
this.handoutsEdit.$el.find('.save-button').click();
|
||||
|
||||
# Verify preview text.
|
||||
expect(@handoutsEdit.$preview.html().trim()).toBe('base-asset-url/image.jpg')
|
||||
// Verify preview text.
|
||||
return expect(this.handoutsEdit.$preview.html().trim()).toBe('base-asset-url/image.jpg');
|
||||
});
|
||||
|
||||
it "shows static links in edit mode", ->
|
||||
# Click edit and verify CodeMirror contents.
|
||||
@handoutsEdit.$el.find('.edit-button').click()
|
||||
expect(@handoutsEdit.$codeMirror.getValue().trim()).toEqual('/static/fromServer.jpg')
|
||||
it("shows static links in edit mode", function() {
|
||||
// Click edit and verify CodeMirror contents.
|
||||
this.handoutsEdit.$el.find('.edit-button').click();
|
||||
return expect(this.handoutsEdit.$codeMirror.getValue().trim()).toEqual('/static/fromServer.jpg');
|
||||
});
|
||||
|
||||
it "can open course handouts with bad html on edit", ->
|
||||
# Enter some bad html in handouts section, verifying that the
|
||||
# model/handoutform opens when "Edit" is clicked
|
||||
return it("can open course handouts with bad html on edit", function() {
|
||||
// Enter some bad html in handouts section, verifying that the
|
||||
// model/handoutform opens when "Edit" is clicked
|
||||
|
||||
@model = new ModuleInfo({
|
||||
this.model = new ModuleInfo({
|
||||
id: 'handouts-id',
|
||||
data: '<p><a href="[URL OF FILE]>[LINK TEXT]</a></p>'
|
||||
})
|
||||
@handoutsEdit = new CourseInfoHandoutsView({
|
||||
});
|
||||
this.handoutsEdit = new CourseInfoHandoutsView({
|
||||
el: $('#course-handouts-view'),
|
||||
model: @model,
|
||||
model: this.model,
|
||||
base_asset_url: 'base-asset-url/'
|
||||
});
|
||||
@handoutsEdit.render()
|
||||
this.handoutsEdit.render();
|
||||
|
||||
expect($('.edit-handouts-form').is(':hidden')).toEqual(true)
|
||||
@handoutsEdit.$el.find('.edit-button').click()
|
||||
expect(@handoutsEdit.$codeMirror.getValue()).toEqual('<p><a href="[URL OF FILE]>[LINK TEXT]</a></p>')
|
||||
expect($('.edit-handouts-form').is(':hidden')).toEqual(false)
|
||||
expect($('.edit-handouts-form').is(':hidden')).toEqual(true);
|
||||
this.handoutsEdit.$el.find('.edit-button').click();
|
||||
expect(this.handoutsEdit.$codeMirror.getValue()).toEqual('<p><a href="[URL OF FILE]>[LINK TEXT]</a></p>');
|
||||
return expect($('.edit-handouts-form').is(':hidden')).toEqual(false);
|
||||
});
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
@@ -1,30 +1,39 @@
|
||||
define ["js/models/metadata", "js/collections/metadata", "js/views/metadata", "cms/js/main"],
|
||||
(MetadataModel, MetadataCollection, MetadataView, main) ->
|
||||
verifyInputType = (input, expectedType) ->
|
||||
# Some browsers (e.g. FireFox) do not support the "number"
|
||||
# input type. We can accept a "text" input instead
|
||||
# and still get acceptable behavior in the UI.
|
||||
if expectedType == 'number' and input.type != 'number'
|
||||
expectedType = 'text'
|
||||
expect(input.type).toBe(expectedType)
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* DS207: Consider shorter variations of null checks
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
define(["js/models/metadata", "js/collections/metadata", "js/views/metadata", "cms/js/main"],
|
||||
function(MetadataModel, MetadataCollection, MetadataView, main) {
|
||||
const verifyInputType = function(input, expectedType) {
|
||||
// Some browsers (e.g. FireFox) do not support the "number"
|
||||
// input type. We can accept a "text" input instead
|
||||
// and still get acceptable behavior in the UI.
|
||||
if ((expectedType === 'number') && (input.type !== 'number')) {
|
||||
expectedType = 'text';
|
||||
}
|
||||
return expect(input.type).toBe(expectedType);
|
||||
};
|
||||
|
||||
describe "Test Metadata Editor", ->
|
||||
editorTemplate = readFixtures('metadata-editor.underscore')
|
||||
numberEntryTemplate = readFixtures('metadata-number-entry.underscore')
|
||||
stringEntryTemplate = readFixtures('metadata-string-entry.underscore')
|
||||
optionEntryTemplate = readFixtures('metadata-option-entry.underscore')
|
||||
listEntryTemplate = readFixtures('metadata-list-entry.underscore')
|
||||
dictEntryTemplate = readFixtures('metadata-dict-entry.underscore')
|
||||
return describe("Test Metadata Editor", function() {
|
||||
const editorTemplate = readFixtures('metadata-editor.underscore');
|
||||
const numberEntryTemplate = readFixtures('metadata-number-entry.underscore');
|
||||
const stringEntryTemplate = readFixtures('metadata-string-entry.underscore');
|
||||
const optionEntryTemplate = readFixtures('metadata-option-entry.underscore');
|
||||
const listEntryTemplate = readFixtures('metadata-list-entry.underscore');
|
||||
const dictEntryTemplate = readFixtures('metadata-dict-entry.underscore');
|
||||
|
||||
beforeEach ->
|
||||
setFixtures($("<script>", {id: "metadata-editor-tpl", type: "text/template"}).text(editorTemplate))
|
||||
appendSetFixtures($("<script>", {id: "metadata-number-entry", type: "text/template"}).text(numberEntryTemplate))
|
||||
appendSetFixtures($("<script>", {id: "metadata-string-entry", type: "text/template"}).text(stringEntryTemplate))
|
||||
appendSetFixtures($("<script>", {id: "metadata-option-entry", type: "text/template"}).text(optionEntryTemplate))
|
||||
appendSetFixtures($("<script>", {id: "metadata-list-entry", type: "text/template"}).text(listEntryTemplate))
|
||||
appendSetFixtures($("<script>", {id: "metadata-dict-entry", type: "text/template"}).text(dictEntryTemplate))
|
||||
beforeEach(function() {
|
||||
setFixtures($("<script>", {id: "metadata-editor-tpl", type: "text/template"}).text(editorTemplate));
|
||||
appendSetFixtures($("<script>", {id: "metadata-number-entry", type: "text/template"}).text(numberEntryTemplate));
|
||||
appendSetFixtures($("<script>", {id: "metadata-string-entry", type: "text/template"}).text(stringEntryTemplate));
|
||||
appendSetFixtures($("<script>", {id: "metadata-option-entry", type: "text/template"}).text(optionEntryTemplate));
|
||||
appendSetFixtures($("<script>", {id: "metadata-list-entry", type: "text/template"}).text(listEntryTemplate));
|
||||
return appendSetFixtures($("<script>", {id: "metadata-dict-entry", type: "text/template"}).text(dictEntryTemplate));
|
||||
});
|
||||
|
||||
genericEntry = {
|
||||
const genericEntry = {
|
||||
default_value: 'default value',
|
||||
display_name: "Display Name",
|
||||
explicitly_set: true,
|
||||
@@ -33,9 +42,9 @@ define ["js/models/metadata", "js/collections/metadata", "js/views/metadata", "c
|
||||
options: [],
|
||||
type: MetadataModel.GENERIC_TYPE,
|
||||
value: "Word cloud"
|
||||
}
|
||||
};
|
||||
|
||||
selectEntry = {
|
||||
const selectEntry = {
|
||||
default_value: "answered",
|
||||
display_name: "Show Answer",
|
||||
explicitly_set: false,
|
||||
@@ -48,9 +57,9 @@ define ["js/models/metadata", "js/collections/metadata", "js/views/metadata", "c
|
||||
],
|
||||
type: MetadataModel.SELECT_TYPE,
|
||||
value: "always"
|
||||
}
|
||||
};
|
||||
|
||||
integerEntry = {
|
||||
const integerEntry = {
|
||||
default_value: 6,
|
||||
display_name: "Inputs",
|
||||
explicitly_set: false,
|
||||
@@ -59,9 +68,9 @@ define ["js/models/metadata", "js/collections/metadata", "js/views/metadata", "c
|
||||
options: {min: 1},
|
||||
type: MetadataModel.INTEGER_TYPE,
|
||||
value: 5
|
||||
}
|
||||
};
|
||||
|
||||
floatEntry = {
|
||||
const floatEntry = {
|
||||
default_value: 2.7,
|
||||
display_name: "Weight",
|
||||
explicitly_set: true,
|
||||
@@ -70,9 +79,9 @@ define ["js/models/metadata", "js/collections/metadata", "js/views/metadata", "c
|
||||
options: {min: 1.3, max:100.2, step:0.1},
|
||||
type: MetadataModel.FLOAT_TYPE,
|
||||
value: 10.2
|
||||
}
|
||||
};
|
||||
|
||||
listEntry = {
|
||||
const listEntry = {
|
||||
default_value: ["a thing", "another thing"],
|
||||
display_name: "List",
|
||||
explicitly_set: false,
|
||||
@@ -81,9 +90,9 @@ define ["js/models/metadata", "js/collections/metadata", "js/views/metadata", "c
|
||||
options: [],
|
||||
type: MetadataModel.LIST_TYPE,
|
||||
value: ["the first display value", "the second"]
|
||||
}
|
||||
};
|
||||
|
||||
timeEntry = {
|
||||
const timeEntry = {
|
||||
default_value: "00:00:00",
|
||||
display_name: "Time",
|
||||
explicitly_set: true,
|
||||
@@ -92,9 +101,9 @@ define ["js/models/metadata", "js/collections/metadata", "js/views/metadata", "c
|
||||
options: [],
|
||||
type: MetadataModel.RELATIVE_TIME_TYPE,
|
||||
value: "12:12:12"
|
||||
}
|
||||
};
|
||||
|
||||
dictEntry = {
|
||||
const dictEntry = {
|
||||
default_value: {
|
||||
'en': 'English',
|
||||
'ru': 'Русский'
|
||||
@@ -110,13 +119,13 @@ define ["js/models/metadata", "js/collections/metadata", "js/views/metadata", "c
|
||||
'ua': 'Українська',
|
||||
'fr': 'Français'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
# Test for the editor that creates the individual views.
|
||||
describe "MetadataView.Editor creates editors for each field", ->
|
||||
beforeEach ->
|
||||
@model = new MetadataCollection(
|
||||
// Test for the editor that creates the individual views.
|
||||
describe("MetadataView.Editor creates editors for each field", function() {
|
||||
beforeEach(function() {
|
||||
return this.model = new MetadataCollection(
|
||||
[
|
||||
integerEntry,
|
||||
floatEntry,
|
||||
@@ -139,36 +148,40 @@ define ["js/models/metadata", "js/collections/metadata", "js/views/metadata", "c
|
||||
timeEntry,
|
||||
dictEntry
|
||||
]
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it "creates child views on initialize, and sorts them alphabetically", ->
|
||||
view = new MetadataView.Editor({collection: @model})
|
||||
childModels = view.collection.models
|
||||
expect(childModels.length).toBe(8)
|
||||
# Be sure to check list view as well as other input types
|
||||
childViews = view.$el.find('.setting-input, .list-settings')
|
||||
expect(childViews.length).toBe(8)
|
||||
it("creates child views on initialize, and sorts them alphabetically", function() {
|
||||
const view = new MetadataView.Editor({collection: this.model});
|
||||
const childModels = view.collection.models;
|
||||
expect(childModels.length).toBe(8);
|
||||
// Be sure to check list view as well as other input types
|
||||
const childViews = view.$el.find('.setting-input, .list-settings');
|
||||
expect(childViews.length).toBe(8);
|
||||
|
||||
verifyEntry = (index, display_name, type) ->
|
||||
expect(childModels[index].get('display_name')).toBe(display_name)
|
||||
verifyInputType(childViews[index], type)
|
||||
const verifyEntry = function(index, display_name, type) {
|
||||
expect(childModels[index].get('display_name')).toBe(display_name);
|
||||
return verifyInputType(childViews[index], type);
|
||||
};
|
||||
|
||||
verifyEntry(0, 'Display Name', 'text')
|
||||
verifyEntry(1, 'Inputs', 'number')
|
||||
verifyEntry(2, 'List', '')
|
||||
verifyEntry(3, 'New Dict', '')
|
||||
verifyEntry(4, 'Show Answer', 'select-one')
|
||||
verifyEntry(5, 'Time', 'text')
|
||||
verifyEntry(6, 'Unknown', 'text')
|
||||
verifyEntry(7, 'Weight', 'number')
|
||||
verifyEntry(0, 'Display Name', 'text');
|
||||
verifyEntry(1, 'Inputs', 'number');
|
||||
verifyEntry(2, 'List', '');
|
||||
verifyEntry(3, 'New Dict', '');
|
||||
verifyEntry(4, 'Show Answer', 'select-one');
|
||||
verifyEntry(5, 'Time', 'text');
|
||||
verifyEntry(6, 'Unknown', 'text');
|
||||
return verifyEntry(7, 'Weight', 'number');
|
||||
});
|
||||
|
||||
it "returns its display name", ->
|
||||
view = new MetadataView.Editor({collection: @model})
|
||||
expect(view.getDisplayName()).toBe("Word cloud")
|
||||
it("returns its display name", function() {
|
||||
const view = new MetadataView.Editor({collection: this.model});
|
||||
return expect(view.getDisplayName()).toBe("Word cloud");
|
||||
});
|
||||
|
||||
it "returns an empty string if there is no display name property with a valid value", ->
|
||||
view = new MetadataView.Editor({collection: new MetadataCollection()})
|
||||
expect(view.getDisplayName()).toBe("")
|
||||
it("returns an empty string if there is no display name property with a valid value", function() {
|
||||
let view = new MetadataView.Editor({collection: new MetadataCollection()});
|
||||
expect(view.getDisplayName()).toBe("");
|
||||
|
||||
view = new MetadataView.Editor({collection: new MetadataCollection([
|
||||
{
|
||||
@@ -182,391 +195,457 @@ define ["js/models/metadata", "js/collections/metadata", "js/views/metadata", "c
|
||||
value: null
|
||||
|
||||
}])
|
||||
})
|
||||
expect(view.getDisplayName()).toBe("")
|
||||
});
|
||||
return expect(view.getDisplayName()).toBe("");
|
||||
});
|
||||
|
||||
it "has no modified values by default", ->
|
||||
view = new MetadataView.Editor({collection: @model})
|
||||
expect(view.getModifiedMetadataValues()).toEqual({})
|
||||
it("has no modified values by default", function() {
|
||||
const view = new MetadataView.Editor({collection: this.model});
|
||||
return expect(view.getModifiedMetadataValues()).toEqual({});
|
||||
});
|
||||
|
||||
it "returns modified values only", ->
|
||||
view = new MetadataView.Editor({collection: @model})
|
||||
childModels = view.collection.models
|
||||
childModels[0].setValue('updated display name')
|
||||
childModels[1].setValue(20)
|
||||
expect(view.getModifiedMetadataValues()).toEqual({
|
||||
return it("returns modified values only", function() {
|
||||
const view = new MetadataView.Editor({collection: this.model});
|
||||
const childModels = view.collection.models;
|
||||
childModels[0].setValue('updated display name');
|
||||
childModels[1].setValue(20);
|
||||
return expect(view.getModifiedMetadataValues()).toEqual({
|
||||
display_name : 'updated display name',
|
||||
num_inputs: 20
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
# Tests for individual views.
|
||||
assertInputType = (view, expectedType) ->
|
||||
input = view.$el.find('.setting-input')
|
||||
expect(input.length).toEqual(1)
|
||||
verifyInputType(input[0], expectedType)
|
||||
// Tests for individual views.
|
||||
const assertInputType = function(view, expectedType) {
|
||||
const input = view.$el.find('.setting-input');
|
||||
expect(input.length).toEqual(1);
|
||||
return verifyInputType(input[0], expectedType);
|
||||
};
|
||||
|
||||
assertValueInView = (view, expectedValue) ->
|
||||
expect(view.getValueFromEditor()).toEqual(expectedValue)
|
||||
const assertValueInView = (view, expectedValue) => expect(view.getValueFromEditor()).toEqual(expectedValue);
|
||||
|
||||
assertCanUpdateView = (view, newValue) ->
|
||||
view.setValueInEditor(newValue)
|
||||
expect(view.getValueFromEditor()).toEqual(newValue)
|
||||
const assertCanUpdateView = function(view, newValue) {
|
||||
view.setValueInEditor(newValue);
|
||||
return expect(view.getValueFromEditor()).toEqual(newValue);
|
||||
};
|
||||
|
||||
assertClear = (view, modelValue, editorValue=modelValue) ->
|
||||
view.clear()
|
||||
expect(view.model.getValue()).toBe(null)
|
||||
expect(view.model.getDisplayValue()).toEqual(modelValue)
|
||||
expect(view.getValueFromEditor()).toEqual(editorValue)
|
||||
const assertClear = function(view, modelValue, editorValue) {
|
||||
if (editorValue == null) { editorValue = modelValue; }
|
||||
view.clear();
|
||||
expect(view.model.getValue()).toBe(null);
|
||||
expect(view.model.getDisplayValue()).toEqual(modelValue);
|
||||
return expect(view.getValueFromEditor()).toEqual(editorValue);
|
||||
};
|
||||
|
||||
assertUpdateModel = (view, originalValue, newValue) ->
|
||||
view.setValueInEditor(newValue)
|
||||
expect(view.model.getValue()).toEqual(originalValue)
|
||||
view.updateModel()
|
||||
expect(view.model.getValue()).toEqual(newValue)
|
||||
const assertUpdateModel = function(view, originalValue, newValue) {
|
||||
view.setValueInEditor(newValue);
|
||||
expect(view.model.getValue()).toEqual(originalValue);
|
||||
view.updateModel();
|
||||
return expect(view.model.getValue()).toEqual(newValue);
|
||||
};
|
||||
|
||||
describe "MetadataView.String is a basic string input with clear functionality", ->
|
||||
beforeEach ->
|
||||
model = new MetadataModel(genericEntry)
|
||||
@view = new MetadataView.String({model: model})
|
||||
describe("MetadataView.String is a basic string input with clear functionality", function() {
|
||||
beforeEach(function() {
|
||||
const model = new MetadataModel(genericEntry);
|
||||
return this.view = new MetadataView.String({model});
|
||||
});
|
||||
|
||||
it "uses a text input type", ->
|
||||
assertInputType(@view, 'text')
|
||||
it("uses a text input type", function() {
|
||||
return assertInputType(this.view, 'text');
|
||||
});
|
||||
|
||||
it "returns the intial value upon initialization", ->
|
||||
assertValueInView(@view, 'Word cloud')
|
||||
it("returns the intial value upon initialization", function() {
|
||||
return assertValueInView(this.view, 'Word cloud');
|
||||
});
|
||||
|
||||
it "can update its value in the view", ->
|
||||
assertCanUpdateView(@view, "updated ' \" &")
|
||||
it("can update its value in the view", function() {
|
||||
return assertCanUpdateView(this.view, "updated ' \" &");
|
||||
});
|
||||
|
||||
it "has a clear method to revert to the model default", ->
|
||||
assertClear(@view, 'default value')
|
||||
it("has a clear method to revert to the model default", function() {
|
||||
return assertClear(this.view, 'default value');
|
||||
});
|
||||
|
||||
it "has an update model method", ->
|
||||
assertUpdateModel(@view, 'Word cloud', 'updated')
|
||||
return it("has an update model method", function() {
|
||||
return assertUpdateModel(this.view, 'Word cloud', 'updated');
|
||||
});
|
||||
});
|
||||
|
||||
describe "MetadataView.Option is an option input type with clear functionality", ->
|
||||
beforeEach ->
|
||||
model = new MetadataModel(selectEntry)
|
||||
@view = new MetadataView.Option({model: model})
|
||||
describe("MetadataView.Option is an option input type with clear functionality", function() {
|
||||
beforeEach(function() {
|
||||
const model = new MetadataModel(selectEntry);
|
||||
return this.view = new MetadataView.Option({model});
|
||||
});
|
||||
|
||||
it "uses a select input type", ->
|
||||
assertInputType(@view, 'select-one')
|
||||
it("uses a select input type", function() {
|
||||
return assertInputType(this.view, 'select-one');
|
||||
});
|
||||
|
||||
it "returns the intial value upon initialization", ->
|
||||
assertValueInView(@view, 'always')
|
||||
it("returns the intial value upon initialization", function() {
|
||||
return assertValueInView(this.view, 'always');
|
||||
});
|
||||
|
||||
it "can update its value in the view", ->
|
||||
assertCanUpdateView(@view, "never")
|
||||
it("can update its value in the view", function() {
|
||||
return assertCanUpdateView(this.view, "never");
|
||||
});
|
||||
|
||||
it "has a clear method to revert to the model default", ->
|
||||
assertClear(@view, 'answered')
|
||||
it("has a clear method to revert to the model default", function() {
|
||||
return assertClear(this.view, 'answered');
|
||||
});
|
||||
|
||||
it "has an update model method", ->
|
||||
assertUpdateModel(@view, null, 'never')
|
||||
it("has an update model method", function() {
|
||||
return assertUpdateModel(this.view, null, 'never');
|
||||
});
|
||||
|
||||
it "does not update to a value that is not an option", ->
|
||||
@view.setValueInEditor("not an option")
|
||||
expect(@view.getValueFromEditor()).toBe('always')
|
||||
return it("does not update to a value that is not an option", function() {
|
||||
this.view.setValueInEditor("not an option");
|
||||
return expect(this.view.getValueFromEditor()).toBe('always');
|
||||
});
|
||||
});
|
||||
|
||||
describe "MetadataView.Number supports integer or float type and has clear functionality", ->
|
||||
verifyValueAfterChanged = (view, value, expectedResult) ->
|
||||
view.setValueInEditor(value)
|
||||
view.changed()
|
||||
expect(view.getValueFromEditor()).toBe(expectedResult)
|
||||
describe("MetadataView.Number supports integer or float type and has clear functionality", function() {
|
||||
const verifyValueAfterChanged = function(view, value, expectedResult) {
|
||||
view.setValueInEditor(value);
|
||||
view.changed();
|
||||
return expect(view.getValueFromEditor()).toBe(expectedResult);
|
||||
};
|
||||
|
||||
beforeEach ->
|
||||
integerModel = new MetadataModel(integerEntry)
|
||||
@integerView = new MetadataView.Number({model: integerModel})
|
||||
beforeEach(function() {
|
||||
const integerModel = new MetadataModel(integerEntry);
|
||||
this.integerView = new MetadataView.Number({model: integerModel});
|
||||
|
||||
floatModel = new MetadataModel(floatEntry)
|
||||
@floatView = new MetadataView.Number({model: floatModel})
|
||||
const floatModel = new MetadataModel(floatEntry);
|
||||
return this.floatView = new MetadataView.Number({model: floatModel});
|
||||
});
|
||||
|
||||
it "uses a number input type", ->
|
||||
assertInputType(@integerView, 'number')
|
||||
assertInputType(@floatView, 'number')
|
||||
it("uses a number input type", function() {
|
||||
assertInputType(this.integerView, 'number');
|
||||
return assertInputType(this.floatView, 'number');
|
||||
});
|
||||
|
||||
it "returns the intial value upon initialization", ->
|
||||
assertValueInView(@integerView, '5')
|
||||
assertValueInView(@floatView, '10.2')
|
||||
it("returns the intial value upon initialization", function() {
|
||||
assertValueInView(this.integerView, '5');
|
||||
return assertValueInView(this.floatView, '10.2');
|
||||
});
|
||||
|
||||
it "can update its value in the view", ->
|
||||
assertCanUpdateView(@integerView, "12")
|
||||
assertCanUpdateView(@floatView, "-2.4")
|
||||
it("can update its value in the view", function() {
|
||||
assertCanUpdateView(this.integerView, "12");
|
||||
return assertCanUpdateView(this.floatView, "-2.4");
|
||||
});
|
||||
|
||||
it "has a clear method to revert to the model default", ->
|
||||
assertClear(@integerView, 6, '6')
|
||||
assertClear(@floatView, 2.7, '2.7')
|
||||
it("has a clear method to revert to the model default", function() {
|
||||
assertClear(this.integerView, 6, '6');
|
||||
return assertClear(this.floatView, 2.7, '2.7');
|
||||
});
|
||||
|
||||
it "has an update model method", ->
|
||||
assertUpdateModel(@integerView, null, '90')
|
||||
assertUpdateModel(@floatView, 10.2, '-9.5')
|
||||
it("has an update model method", function() {
|
||||
assertUpdateModel(this.integerView, null, '90');
|
||||
return assertUpdateModel(this.floatView, 10.2, '-9.5');
|
||||
});
|
||||
|
||||
it "knows the difference between integer and float", ->
|
||||
expect(@integerView.isIntegerField()).toBeTruthy()
|
||||
expect(@floatView.isIntegerField()).toBeFalsy()
|
||||
it("knows the difference between integer and float", function() {
|
||||
expect(this.integerView.isIntegerField()).toBeTruthy();
|
||||
return expect(this.floatView.isIntegerField()).toBeFalsy();
|
||||
});
|
||||
|
||||
it "sets attribtues related to min, max, and step", ->
|
||||
verifyAttributes = (view, min, step, max=null) ->
|
||||
inputEntry = view.$el.find('input')
|
||||
expect(Number(inputEntry.attr('min'))).toEqual(min)
|
||||
expect(Number(inputEntry.attr('step'))).toEqual(step)
|
||||
if max is not null
|
||||
expect(Number(inputEntry.attr('max'))).toEqual(max)
|
||||
it("sets attribtues related to min, max, and step", function() {
|
||||
const verifyAttributes = function(view, min, step, max=null) {
|
||||
const inputEntry = view.$el.find('input');
|
||||
expect(Number(inputEntry.attr('min'))).toEqual(min);
|
||||
expect(Number(inputEntry.attr('step'))).toEqual(step);
|
||||
if (max === !null) {
|
||||
return expect(Number(inputEntry.attr('max'))).toEqual(max);
|
||||
}
|
||||
};
|
||||
|
||||
verifyAttributes(@integerView, 1, 1)
|
||||
verifyAttributes(@floatView, 1.3, .1, 100.2)
|
||||
verifyAttributes(this.integerView, 1, 1);
|
||||
return verifyAttributes(this.floatView, 1.3, .1, 100.2);
|
||||
});
|
||||
|
||||
it "corrects values that are out of range", ->
|
||||
verifyValueAfterChanged(@integerView, '-4', '1')
|
||||
verifyValueAfterChanged(@integerView, '1', '1')
|
||||
verifyValueAfterChanged(@integerView, '0', '1')
|
||||
verifyValueAfterChanged(@integerView, '3001', '3001')
|
||||
it("corrects values that are out of range", function() {
|
||||
verifyValueAfterChanged(this.integerView, '-4', '1');
|
||||
verifyValueAfterChanged(this.integerView, '1', '1');
|
||||
verifyValueAfterChanged(this.integerView, '0', '1');
|
||||
verifyValueAfterChanged(this.integerView, '3001', '3001');
|
||||
|
||||
verifyValueAfterChanged(@floatView, '-4', '1.3')
|
||||
verifyValueAfterChanged(@floatView, '1.3', '1.3')
|
||||
verifyValueAfterChanged(@floatView, '1.2', '1.3')
|
||||
verifyValueAfterChanged(@floatView, '100.2', '100.2')
|
||||
verifyValueAfterChanged(@floatView, '100.3', '100.2')
|
||||
verifyValueAfterChanged(this.floatView, '-4', '1.3');
|
||||
verifyValueAfterChanged(this.floatView, '1.3', '1.3');
|
||||
verifyValueAfterChanged(this.floatView, '1.2', '1.3');
|
||||
verifyValueAfterChanged(this.floatView, '100.2', '100.2');
|
||||
return verifyValueAfterChanged(this.floatView, '100.3', '100.2');
|
||||
});
|
||||
|
||||
it "sets default values for integer and float fields that are empty", ->
|
||||
verifyValueAfterChanged(@integerView, '', '6')
|
||||
verifyValueAfterChanged(@floatView, '', '2.7')
|
||||
it("sets default values for integer and float fields that are empty", function() {
|
||||
verifyValueAfterChanged(this.integerView, '', '6');
|
||||
return verifyValueAfterChanged(this.floatView, '', '2.7');
|
||||
});
|
||||
|
||||
it "disallows invalid characters", ->
|
||||
verifyValueAfterKeyPressed = (view, character, reject) ->
|
||||
event = {
|
||||
return it("disallows invalid characters", function() {
|
||||
const verifyValueAfterKeyPressed = function(view, character, reject) {
|
||||
const event = {
|
||||
type : 'keypress',
|
||||
which : character.charCodeAt(0),
|
||||
keyCode: character.charCodeAt(0),
|
||||
preventDefault : () -> 'no op'
|
||||
preventDefault() { return 'no op'; }
|
||||
};
|
||||
spyOn(event, 'preventDefault');
|
||||
view.$el.find('input').trigger(event);
|
||||
if (reject) {
|
||||
return expect(event.preventDefault).toHaveBeenCalled();
|
||||
} else {
|
||||
return expect(event.preventDefault).not.toHaveBeenCalled();
|
||||
}
|
||||
spyOn(event, 'preventDefault')
|
||||
view.$el.find('input').trigger(event)
|
||||
if (reject)
|
||||
expect(event.preventDefault).toHaveBeenCalled()
|
||||
else
|
||||
expect(event.preventDefault).not.toHaveBeenCalled()
|
||||
};
|
||||
|
||||
verifyDisallowedChars = (view) ->
|
||||
verifyValueAfterKeyPressed(view, 'a', true)
|
||||
verifyValueAfterKeyPressed(view, '.', view.isIntegerField())
|
||||
verifyValueAfterKeyPressed(view, '[', true)
|
||||
verifyValueAfterKeyPressed(view, '@', true)
|
||||
const verifyDisallowedChars = function(view) {
|
||||
verifyValueAfterKeyPressed(view, 'a', true);
|
||||
verifyValueAfterKeyPressed(view, '.', view.isIntegerField());
|
||||
verifyValueAfterKeyPressed(view, '[', true);
|
||||
verifyValueAfterKeyPressed(view, '@', true);
|
||||
|
||||
for i in [0...9]
|
||||
verifyValueAfterKeyPressed(view, String(i), false)
|
||||
return [0, 1, 2, 3, 4, 5, 6, 7, 8].map((i) =>
|
||||
verifyValueAfterKeyPressed(view, String(i), false));
|
||||
};
|
||||
|
||||
verifyDisallowedChars(@integerView)
|
||||
verifyDisallowedChars(@floatView)
|
||||
verifyDisallowedChars(this.integerView);
|
||||
return verifyDisallowedChars(this.floatView);
|
||||
});
|
||||
});
|
||||
|
||||
describe "MetadataView.List allows the user to enter an ordered list of strings", ->
|
||||
beforeEach ->
|
||||
listModel = new MetadataModel(listEntry)
|
||||
@listView = new MetadataView.List({model: listModel})
|
||||
@el = @listView.$el
|
||||
main()
|
||||
describe("MetadataView.List allows the user to enter an ordered list of strings", function() {
|
||||
beforeEach(function() {
|
||||
const listModel = new MetadataModel(listEntry);
|
||||
this.listView = new MetadataView.List({model: listModel});
|
||||
this.el = this.listView.$el;
|
||||
return main();
|
||||
});
|
||||
|
||||
it "returns the initial value upon initialization", ->
|
||||
assertValueInView(@listView, ['the first display value', 'the second'])
|
||||
it("returns the initial value upon initialization", function() {
|
||||
return assertValueInView(this.listView, ['the first display value', 'the second']);
|
||||
});
|
||||
|
||||
it "updates its value correctly", ->
|
||||
assertCanUpdateView(@listView, ['a new item', 'another new item', 'a third'])
|
||||
it("updates its value correctly", function() {
|
||||
return assertCanUpdateView(this.listView, ['a new item', 'another new item', 'a third']);
|
||||
});
|
||||
|
||||
it "has a clear method to revert to the model default", ->
|
||||
@el.find('.create-setting').click()
|
||||
assertClear(@listView, ['a thing', 'another thing'])
|
||||
expect(@el.find('.create-setting')).not.toHaveClass('is-disabled')
|
||||
it("has a clear method to revert to the model default", function() {
|
||||
this.el.find('.create-setting').click();
|
||||
assertClear(this.listView, ['a thing', 'another thing']);
|
||||
return expect(this.el.find('.create-setting')).not.toHaveClass('is-disabled');
|
||||
});
|
||||
|
||||
it "has an update model method", ->
|
||||
assertUpdateModel(@listView, null, ['a new value'])
|
||||
it("has an update model method", function() {
|
||||
return assertUpdateModel(this.listView, null, ['a new value']);
|
||||
});
|
||||
|
||||
it "can add an entry", ->
|
||||
expect(@listView.model.get('value').length).toEqual(2)
|
||||
@el.find('.create-setting').click()
|
||||
expect(@el.find('input.input').length).toEqual(3)
|
||||
it("can add an entry", function() {
|
||||
expect(this.listView.model.get('value').length).toEqual(2);
|
||||
this.el.find('.create-setting').click();
|
||||
return expect(this.el.find('input.input').length).toEqual(3);
|
||||
});
|
||||
|
||||
it "can remove an entry", ->
|
||||
expect(@listView.model.get('value').length).toEqual(2)
|
||||
@el.find('.remove-setting').first().click()
|
||||
expect(@listView.model.get('value').length).toEqual(1)
|
||||
it("can remove an entry", function() {
|
||||
expect(this.listView.model.get('value').length).toEqual(2);
|
||||
this.el.find('.remove-setting').first().click();
|
||||
return expect(this.listView.model.get('value').length).toEqual(1);
|
||||
});
|
||||
|
||||
it "only allows one blank entry at a time", ->
|
||||
expect(@el.find('input').length).toEqual(2)
|
||||
@el.find('.create-setting').click()
|
||||
@el.find('.create-setting').click()
|
||||
expect(@el.find('input').length).toEqual(3)
|
||||
it("only allows one blank entry at a time", function() {
|
||||
expect(this.el.find('input').length).toEqual(2);
|
||||
this.el.find('.create-setting').click();
|
||||
this.el.find('.create-setting').click();
|
||||
return expect(this.el.find('input').length).toEqual(3);
|
||||
});
|
||||
|
||||
it "re-enables the add setting button after entering a new value", ->
|
||||
expect(@el.find('input').length).toEqual(2)
|
||||
@el.find('.create-setting').click()
|
||||
expect(@el.find('.create-setting')).toHaveClass('is-disabled')
|
||||
@el.find('input').last().val('third setting')
|
||||
@el.find('input').last().trigger('input')
|
||||
expect(@el.find('.create-setting')).not.toHaveClass('is-disabled')
|
||||
return it("re-enables the add setting button after entering a new value", function() {
|
||||
expect(this.el.find('input').length).toEqual(2);
|
||||
this.el.find('.create-setting').click();
|
||||
expect(this.el.find('.create-setting')).toHaveClass('is-disabled');
|
||||
this.el.find('input').last().val('third setting');
|
||||
this.el.find('input').last().trigger('input');
|
||||
return expect(this.el.find('.create-setting')).not.toHaveClass('is-disabled');
|
||||
});
|
||||
});
|
||||
|
||||
describe "MetadataView.RelativeTime allows the user to enter time string in HH:mm:ss format", ->
|
||||
beforeEach ->
|
||||
model = new MetadataModel(timeEntry)
|
||||
@view = new MetadataView.RelativeTime({model: model})
|
||||
describe("MetadataView.RelativeTime allows the user to enter time string in HH:mm:ss format", function() {
|
||||
beforeEach(function() {
|
||||
const model = new MetadataModel(timeEntry);
|
||||
return this.view = new MetadataView.RelativeTime({model});
|
||||
});
|
||||
|
||||
it "uses a text input type", ->
|
||||
assertInputType(@view, 'text')
|
||||
it("uses a text input type", function() {
|
||||
return assertInputType(this.view, 'text');
|
||||
});
|
||||
|
||||
it "returns the intial value upon initialization", ->
|
||||
assertValueInView(@view, '12:12:12')
|
||||
it("returns the intial value upon initialization", function() {
|
||||
return assertValueInView(this.view, '12:12:12');
|
||||
});
|
||||
|
||||
it "value is converted correctly", ->
|
||||
view = @view
|
||||
it("value is converted correctly", function() {
|
||||
const { view } = this;
|
||||
|
||||
cases = [
|
||||
const cases = [
|
||||
{
|
||||
input: '23:100:0'
|
||||
input: '23:100:0',
|
||||
output: '23:59:59'
|
||||
},
|
||||
{
|
||||
input: '100000000000000000'
|
||||
input: '100000000000000000',
|
||||
output: '23:59:59'
|
||||
},
|
||||
{
|
||||
input: '80000'
|
||||
input: '80000',
|
||||
output: '22:13:20'
|
||||
},
|
||||
{
|
||||
input: '-100'
|
||||
input: '-100',
|
||||
output: '00:00:00'
|
||||
},
|
||||
{
|
||||
input: '-100:-10'
|
||||
input: '-100:-10',
|
||||
output: '00:00:00'
|
||||
},
|
||||
{
|
||||
input: '99:99'
|
||||
input: '99:99',
|
||||
output: '01:40:39'
|
||||
},
|
||||
{
|
||||
input: '2'
|
||||
input: '2',
|
||||
output: '00:00:02'
|
||||
},
|
||||
{
|
||||
input: '1:2'
|
||||
input: '1:2',
|
||||
output: '00:01:02'
|
||||
},
|
||||
{
|
||||
input: '1:25'
|
||||
input: '1:25',
|
||||
output: '00:01:25'
|
||||
},
|
||||
{
|
||||
input: '3:1:25'
|
||||
input: '3:1:25',
|
||||
output: '03:01:25'
|
||||
},
|
||||
{
|
||||
input: ' 2 3 : 5 9 : 5 9 '
|
||||
input: ' 2 3 : 5 9 : 5 9 ',
|
||||
output: '23:59:59'
|
||||
},
|
||||
{
|
||||
input: '9:1:25'
|
||||
input: '9:1:25',
|
||||
output: '09:01:25'
|
||||
},
|
||||
{
|
||||
input: '77:72:77'
|
||||
input: '77:72:77',
|
||||
output: '23:59:59'
|
||||
},
|
||||
{
|
||||
input: '22:100:100'
|
||||
input: '22:100:100',
|
||||
output: '23:41:40'
|
||||
},
|
||||
# negative value
|
||||
// negative value
|
||||
{
|
||||
input: '-22:22:22'
|
||||
input: '-22:22:22',
|
||||
output: '00:22:22'
|
||||
},
|
||||
# simple string
|
||||
// simple string
|
||||
{
|
||||
input: 'simple text'
|
||||
input: 'simple text',
|
||||
output: '00:00:00'
|
||||
},
|
||||
{
|
||||
input: 'a10a:a10a:a10a'
|
||||
input: 'a10a:a10a:a10a',
|
||||
output: '00:00:00'
|
||||
},
|
||||
# empty string
|
||||
// empty string
|
||||
{
|
||||
input: ''
|
||||
input: '',
|
||||
output: '00:00:00'
|
||||
}
|
||||
]
|
||||
];
|
||||
|
||||
$.each cases, (index, data) ->
|
||||
expect(view.parseRelativeTime(data.input)).toBe(data.output)
|
||||
return $.each(cases, (index, data) => expect(view.parseRelativeTime(data.input)).toBe(data.output));
|
||||
});
|
||||
|
||||
it "can update its value in the view", ->
|
||||
assertCanUpdateView(@view, "23:59:59")
|
||||
@view.setValueInEditor("33:59:59")
|
||||
@view.updateModel()
|
||||
assertValueInView(@view, "23:59:59")
|
||||
it("can update its value in the view", function() {
|
||||
assertCanUpdateView(this.view, "23:59:59");
|
||||
this.view.setValueInEditor("33:59:59");
|
||||
this.view.updateModel();
|
||||
return assertValueInView(this.view, "23:59:59");
|
||||
});
|
||||
|
||||
it "has a clear method to revert to the model default", ->
|
||||
assertClear(@view, '00:00:00')
|
||||
it("has a clear method to revert to the model default", function() {
|
||||
return assertClear(this.view, '00:00:00');
|
||||
});
|
||||
|
||||
it "has an update model method", ->
|
||||
assertUpdateModel(@view, '12:12:12', '23:59:59')
|
||||
return it("has an update model method", function() {
|
||||
return assertUpdateModel(this.view, '12:12:12', '23:59:59');
|
||||
});
|
||||
});
|
||||
|
||||
describe "MetadataView.Dict allows the user to enter key-value pairs of strings", ->
|
||||
beforeEach ->
|
||||
dictModel = new MetadataModel($.extend(true, {}, dictEntry))
|
||||
@dictView = new MetadataView.Dict({model: dictModel})
|
||||
@el = @dictView.$el
|
||||
main()
|
||||
return describe("MetadataView.Dict allows the user to enter key-value pairs of strings", function() {
|
||||
beforeEach(function() {
|
||||
const dictModel = new MetadataModel($.extend(true, {}, dictEntry));
|
||||
this.dictView = new MetadataView.Dict({model: dictModel});
|
||||
this.el = this.dictView.$el;
|
||||
return main();
|
||||
});
|
||||
|
||||
it "returns the initial value upon initialization", ->
|
||||
assertValueInView(@dictView, {
|
||||
it("returns the initial value upon initialization", function() {
|
||||
return assertValueInView(this.dictView, {
|
||||
'en': 'English',
|
||||
'ru': 'Русский',
|
||||
'ua': 'Українська',
|
||||
'fr': 'Français'
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
it "updates its value correctly", ->
|
||||
assertCanUpdateView(@dictView, {
|
||||
it("updates its value correctly", function() {
|
||||
return assertCanUpdateView(this.dictView, {
|
||||
'ru': 'Русский',
|
||||
'ua': 'Українська',
|
||||
'fr': 'Français'
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
it "has a clear method to revert to the model default", ->
|
||||
@el.find('.create-setting').click()
|
||||
assertClear(@dictView, {
|
||||
it("has a clear method to revert to the model default", function() {
|
||||
this.el.find('.create-setting').click();
|
||||
assertClear(this.dictView, {
|
||||
'en': 'English',
|
||||
'ru': 'Русский'
|
||||
})
|
||||
expect(@el.find('.create-setting')).not.toHaveClass('is-disabled')
|
||||
});
|
||||
return expect(this.el.find('.create-setting')).not.toHaveClass('is-disabled');
|
||||
});
|
||||
|
||||
it "has an update model method", ->
|
||||
assertUpdateModel(@dictView, null, {'fr': 'Français'})
|
||||
it("has an update model method", function() {
|
||||
return assertUpdateModel(this.dictView, null, {'fr': 'Français'});
|
||||
});
|
||||
|
||||
it "can add an entry", ->
|
||||
expect(_.keys(@dictView.model.get('value')).length).toEqual(4)
|
||||
@el.find('.create-setting').click()
|
||||
expect(@el.find('input.input-key').length).toEqual(5)
|
||||
it("can add an entry", function() {
|
||||
expect(_.keys(this.dictView.model.get('value')).length).toEqual(4);
|
||||
this.el.find('.create-setting').click();
|
||||
return expect(this.el.find('input.input-key').length).toEqual(5);
|
||||
});
|
||||
|
||||
it "can remove an entry", ->
|
||||
expect(_.keys(@dictView.model.get('value')).length).toEqual(4)
|
||||
@el.find('.remove-setting').first().click()
|
||||
expect(_.keys(@dictView.model.get('value')).length).toEqual(3)
|
||||
it("can remove an entry", function() {
|
||||
expect(_.keys(this.dictView.model.get('value')).length).toEqual(4);
|
||||
this.el.find('.remove-setting').first().click();
|
||||
return expect(_.keys(this.dictView.model.get('value')).length).toEqual(3);
|
||||
});
|
||||
|
||||
it "only allows one blank entry at a time", ->
|
||||
expect(@el.find('input.input-key').length).toEqual(4)
|
||||
@el.find('.create-setting').click()
|
||||
@el.find('.create-setting').click()
|
||||
expect(@el.find('input.input-key').length).toEqual(5)
|
||||
it("only allows one blank entry at a time", function() {
|
||||
expect(this.el.find('input.input-key').length).toEqual(4);
|
||||
this.el.find('.create-setting').click();
|
||||
this.el.find('.create-setting').click();
|
||||
return expect(this.el.find('input.input-key').length).toEqual(5);
|
||||
});
|
||||
|
||||
it "only allows unique keys", ->
|
||||
data = [
|
||||
it("only allows unique keys", function() {
|
||||
const data = [
|
||||
{
|
||||
expectedValue: {'ru': 'Русский'},
|
||||
initialValue: {'ru': 'Русский'},
|
||||
testValue: {
|
||||
'key': 'ru'
|
||||
'key': 'ru',
|
||||
'value': ''
|
||||
}
|
||||
},
|
||||
@@ -574,7 +653,7 @@ define ["js/models/metadata", "js/collections/metadata", "js/views/metadata", "c
|
||||
expectedValue: {'ru': 'Русский'},
|
||||
initialValue: {'ru': 'Some value'},
|
||||
testValue: {
|
||||
'key': 'ru'
|
||||
'key': 'ru',
|
||||
'value': 'Русский'
|
||||
}
|
||||
},
|
||||
@@ -582,27 +661,33 @@ define ["js/models/metadata", "js/collections/metadata", "js/views/metadata", "c
|
||||
expectedValue: {'ru': 'Русский'},
|
||||
initialValue: {'ru': 'Русский'},
|
||||
testValue: {
|
||||
'key': ''
|
||||
'key': '',
|
||||
'value': ''
|
||||
}
|
||||
}
|
||||
]
|
||||
];
|
||||
|
||||
_.each data, ((d, index) ->
|
||||
@dictView.setValueInEditor(d.initialValue)
|
||||
@dictView.updateModel();
|
||||
@el.find('.create-setting').click()
|
||||
item = @el.find('.list-settings-item').last()
|
||||
return _.each(data, ((d, index) => {
|
||||
this.dictView.setValueInEditor(d.initialValue);
|
||||
this.dictView.updateModel();
|
||||
this.el.find('.create-setting').click();
|
||||
const item = this.el.find('.list-settings-item').last();
|
||||
item.find('.input-key').val(d.testValue.key);
|
||||
item.find('.input-value').val(d.testValue.value);
|
||||
|
||||
expect(@dictView.getValueFromEditor()).toEqual(d.expectedValue)
|
||||
).bind(@)
|
||||
return expect(this.dictView.getValueFromEditor()).toEqual(d.expectedValue);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it "re-enables the add setting button after entering a new value", ->
|
||||
expect(@el.find('input.input-key').length).toEqual(4)
|
||||
@el.find('.create-setting').click()
|
||||
expect(@el.find('.create-setting')).toHaveClass('is-disabled')
|
||||
@el.find('input.input-key').last().val('third setting')
|
||||
@el.find('input.input-key').last().trigger('input')
|
||||
expect(@el.find('.create-setting')).not.toHaveClass('is-disabled')
|
||||
return it("re-enables the add setting button after entering a new value", function() {
|
||||
expect(this.el.find('input.input-key').length).toEqual(4);
|
||||
this.el.find('.create-setting').click();
|
||||
expect(this.el.find('.create-setting')).toHaveClass('is-disabled');
|
||||
this.el.find('input.input-key').last().val('third setting');
|
||||
this.el.find('input.input-key').last().trigger('input');
|
||||
return expect(this.el.find('.create-setting')).not.toHaveClass('is-disabled');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,27 +1,32 @@
|
||||
define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js/models/course",
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
define(["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js/models/course",
|
||||
"js/collections/textbook", "js/views/show_textbook", "js/views/edit_textbook", "js/views/list_textbooks",
|
||||
"js/views/edit_chapter", "common/js/components/views/feedback_prompt",
|
||||
"common/js/components/views/feedback_notification", "common/js/components/utils/view_utils",
|
||||
"edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers",
|
||||
"js/spec_helpers/modal_helpers"],
|
||||
(Textbook, Chapter, ChapterSet, Course, TextbookSet, ShowTextbook, EditTextbook, ListTextbooks, EditChapter,
|
||||
Prompt, Notification, ViewUtils, AjaxHelpers, modal_helpers) ->
|
||||
function(Textbook, Chapter, ChapterSet, Course, TextbookSet, ShowTextbook, EditTextbook, ListTextbooks, EditChapter,
|
||||
Prompt, Notification, ViewUtils, AjaxHelpers, modal_helpers) {
|
||||
|
||||
describe "ShowTextbook", ->
|
||||
tpl = readFixtures('show-textbook.underscore')
|
||||
describe("ShowTextbook", function() {
|
||||
const tpl = readFixtures('show-textbook.underscore');
|
||||
|
||||
beforeEach ->
|
||||
setFixtures($("<script>", {id: "show-textbook-tpl", type: "text/template"}).text(tpl))
|
||||
appendSetFixtures(sandbox({id: "page-notification"}))
|
||||
appendSetFixtures(sandbox({id: "page-prompt"}))
|
||||
@model = new Textbook({name: "Life Sciences", id: "0life-sciences"})
|
||||
spyOn(@model, "destroy").and.callThrough()
|
||||
@collection = new TextbookSet([@model])
|
||||
@view = new ShowTextbook({model: @model})
|
||||
beforeEach(function() {
|
||||
setFixtures($("<script>", {id: "show-textbook-tpl", type: "text/template"}).text(tpl));
|
||||
appendSetFixtures(sandbox({id: "page-notification"}));
|
||||
appendSetFixtures(sandbox({id: "page-prompt"}));
|
||||
this.model = new Textbook({name: "Life Sciences", id: "0life-sciences"});
|
||||
spyOn(this.model, "destroy").and.callThrough();
|
||||
this.collection = new TextbookSet([this.model]);
|
||||
this.view = new ShowTextbook({model: this.model});
|
||||
|
||||
@promptSpies = jasmine.stealth.spyOnConstructor(Prompt, "Warning", ["show", "hide"])
|
||||
@promptSpies.show.and.returnValue(@promptSpies)
|
||||
window.course = new Course({
|
||||
this.promptSpies = jasmine.stealth.spyOnConstructor(Prompt, "Warning", ["show", "hide"]);
|
||||
this.promptSpies.show.and.returnValue(this.promptSpies);
|
||||
return window.course = new Course({
|
||||
id: "5",
|
||||
name: "Course Name",
|
||||
url_name: "course_name",
|
||||
@@ -29,313 +34,347 @@ define ["js/models/textbook", "js/models/chapter", "js/collections/chapter", "js
|
||||
num: "course_num",
|
||||
revision: "course_rev"
|
||||
});
|
||||
});
|
||||
|
||||
afterEach ->
|
||||
delete window.course
|
||||
afterEach(() => delete window.course);
|
||||
|
||||
describe "Basic", ->
|
||||
it "should render properly", ->
|
||||
@view.render()
|
||||
expect(@view.$el).toContainText("Life Sciences")
|
||||
describe("Basic", function() {
|
||||
it("should render properly", function() {
|
||||
this.view.render();
|
||||
return expect(this.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 set the 'editing' property on the model when the edit button is clicked", function() {
|
||||
this.view.render().$(".edit").click();
|
||||
return expect(this.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.calls.mostRecent().args[0]
|
||||
expect(ctorOptions.title).toMatch(/Life Sciences/)
|
||||
# hasn't actually been removed
|
||||
expect(@model.destroy).not.toHaveBeenCalled()
|
||||
expect(@collection).toContain(@model)
|
||||
it("should pop a delete confirmation when the delete button is clicked", function() {
|
||||
this.view.render().$(".delete").click();
|
||||
expect(this.promptSpies.constructor).toHaveBeenCalled();
|
||||
const ctorOptions = this.promptSpies.constructor.calls.mostRecent().args[0];
|
||||
expect(ctorOptions.title).toMatch(/Life Sciences/);
|
||||
// hasn't actually been removed
|
||||
expect(this.model.destroy).not.toHaveBeenCalled();
|
||||
return expect(this.collection).toContain(this.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 show chapters appropriately", function() {
|
||||
this.model.get("chapters").add([{}, {}, {}]);
|
||||
this.model.set('showChapters', false);
|
||||
this.view.render().$(".show-chapters").click();
|
||||
return expect(this.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()
|
||||
return it("should hide chapters appropriately", function() {
|
||||
this.model.get("chapters").add([{}, {}, {}]);
|
||||
this.model.set('showChapters', true);
|
||||
this.view.render().$(".hide-chapters").click();
|
||||
return expect(this.model.get('showChapters')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe "AJAX", ->
|
||||
beforeEach ->
|
||||
@savingSpies = jasmine.stealth.spyOnConstructor(Notification, "Mini",
|
||||
["show", "hide"])
|
||||
@savingSpies.show.and.returnValue(@savingSpies)
|
||||
CMS.URL.TEXTBOOKS = "/textbooks"
|
||||
return describe("AJAX", function() {
|
||||
beforeEach(function() {
|
||||
this.savingSpies = jasmine.stealth.spyOnConstructor(Notification, "Mini",
|
||||
["show", "hide"]);
|
||||
this.savingSpies.show.and.returnValue(this.savingSpies);
|
||||
return CMS.URL.TEXTBOOKS = "/textbooks";
|
||||
});
|
||||
|
||||
afterEach ->
|
||||
delete CMS.URL.TEXTBOOKS
|
||||
afterEach(() => delete CMS.URL.TEXTBOOKS);
|
||||
|
||||
it "should destroy itself on confirmation", ->
|
||||
requests = AjaxHelpers["requests"](this)
|
||||
return it("should destroy itself on confirmation", function() {
|
||||
const requests = AjaxHelpers["requests"](this);
|
||||
|
||||
@view.render().$(".delete").click()
|
||||
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
|
||||
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.calls.mostRecent().args[0]
|
||||
expect(savingOptions.title).toMatch(/Deleting/)
|
||||
# return a success response
|
||||
requests[0].respond(204)
|
||||
expect(@savingSpies.hide).toHaveBeenCalled()
|
||||
expect(@collection.contains(@model)).toBeFalsy()
|
||||
this.view.render().$(".delete").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.savingSpies.constructor).toHaveBeenCalled();
|
||||
expect(this.savingSpies.show).toHaveBeenCalled();
|
||||
expect(this.savingSpies.hide).not.toHaveBeenCalled();
|
||||
const savingOptions = this.savingSpies.constructor.calls.mostRecent().args[0];
|
||||
expect(savingOptions.title).toMatch(/Deleting/);
|
||||
// return a success response
|
||||
requests[0].respond(204);
|
||||
expect(this.savingSpies.hide).toHaveBeenCalled();
|
||||
return expect(this.collection.contains(this.model)).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe "EditTextbook", ->
|
||||
describe "Basic", ->
|
||||
tpl = readFixtures('edit-textbook.underscore')
|
||||
describe("EditTextbook", () =>
|
||||
describe("Basic", function() {
|
||||
const tpl = readFixtures('edit-textbook.underscore');
|
||||
|
||||
beforeEach ->
|
||||
setFixtures($("<script>", {id: "edit-textbook-tpl", type: "text/template"}).text(tpl))
|
||||
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').and.callThrough()
|
||||
beforeEach(function() {
|
||||
setFixtures($("<script>", {id: "edit-textbook-tpl", type: "text/template"}).text(tpl));
|
||||
appendSetFixtures(sandbox({id: "page-notification"}));
|
||||
appendSetFixtures(sandbox({id: "page-prompt"}));
|
||||
this.model = new Textbook({name: "Life Sciences", editing: true});
|
||||
spyOn(this.model, 'save');
|
||||
this.collection = new TextbookSet();
|
||||
this.collection.add(this.model);
|
||||
this.view = new EditTextbook({model: this.model});
|
||||
return spyOn(this.view, 'render').and.callThrough();
|
||||
});
|
||||
|
||||
it "should render properly", ->
|
||||
@view.render()
|
||||
expect(@view.$("input[name=textbook-name]").val()).toEqual("Life Sciences")
|
||||
it("should render properly", function() {
|
||||
this.view.render();
|
||||
return expect(this.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 allow you to create new empty chapters", function() {
|
||||
this.view.render();
|
||||
const numChapters = this.model.get("chapters").length;
|
||||
this.view.$(".action-add-chapter").click();
|
||||
expect(this.model.get("chapters").length).toEqual(numChapters+1);
|
||||
return expect(this.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 save properly", function() {
|
||||
this.view.render();
|
||||
this.view.$("input[name=textbook-name]").val("starfish");
|
||||
this.view.$("input[name=chapter1-name]").val("wallflower");
|
||||
this.view.$("input[name=chapter1-asset-path]").val("foobar");
|
||||
this.view.$("form").submit();
|
||||
expect(this.model.get("name")).toEqual("starfish");
|
||||
const chapter = this.model.get("chapters").first();
|
||||
expect(chapter.get("name")).toEqual("wallflower");
|
||||
expect(chapter.get("asset_path")).toEqual("foobar");
|
||||
return expect(this.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("should not save on invalid", function() {
|
||||
this.view.render();
|
||||
this.view.$("input[name=textbook-name]").val("");
|
||||
this.view.$("input[name=chapter1-asset-path]").val("foobar.pdf");
|
||||
this.view.$("form").submit();
|
||||
expect(this.model.validationError).toBeTruthy();
|
||||
return expect(this.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("does not save on cancel", function() {
|
||||
this.model.get("chapters").add([{name: "a", asset_path: "b"}]);
|
||||
this.view.render();
|
||||
this.view.$("input[name=textbook-name]").val("starfish");
|
||||
this.view.$("input[name=chapter1-asset-path]").val("foobar.pdf");
|
||||
this.view.$(".action-cancel").click();
|
||||
expect(this.model.get("name")).not.toEqual("starfish");
|
||||
const chapter = this.model.get("chapters").first();
|
||||
expect(chapter.get("asset_path")).not.toEqual("foobar");
|
||||
return expect(this.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("should be possible to correct validation errors", function() {
|
||||
this.view.render();
|
||||
this.view.$("input[name=textbook-name]").val("");
|
||||
this.view.$("input[name=chapter1-asset-path]").val("foobar.pdf");
|
||||
this.view.$("form").submit();
|
||||
expect(this.model.validationError).toBeTruthy();
|
||||
expect(this.model.save).not.toHaveBeenCalled();
|
||||
this.view.$("input[name=textbook-name]").val("starfish");
|
||||
this.view.$("input[name=chapter1-name]").val("foobar");
|
||||
this.view.$("form").submit();
|
||||
expect(this.model.validationError).toBeFalsy();
|
||||
return expect(this.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 if the model has a non-empty chapter", function() {
|
||||
const chapters = this.model.get("chapters");
|
||||
chapters.at(0).set("name", "non-empty");
|
||||
this.model.setOriginalAttributes();
|
||||
this.view.render();
|
||||
chapters.add([{}, {}, {}]); // add three empty chapters
|
||||
expect(chapters.length).toEqual(4);
|
||||
this.view.$(".action-cancel").click();
|
||||
expect(chapters.length).toEqual(1);
|
||||
return 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)
|
||||
return it("removes all empty chapters on cancel except one if the model has no non-empty chapters", function() {
|
||||
const chapters = this.model.get("chapters");
|
||||
this.view.render();
|
||||
chapters.add([{}, {}, {}]); // add three empty chapters
|
||||
expect(chapters.length).toEqual(4);
|
||||
this.view.$(".action-cancel").click();
|
||||
return expect(chapters.length).toEqual(1);
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
describe "ListTextbooks", ->
|
||||
noTextbooksTpl = readFixtures("no-textbooks.underscore")
|
||||
editTextbooktpl = readFixtures('edit-textbook.underscore')
|
||||
describe("ListTextbooks", function() {
|
||||
const noTextbooksTpl = readFixtures("no-textbooks.underscore");
|
||||
const editTextbooktpl = readFixtures('edit-textbook.underscore');
|
||||
|
||||
beforeEach ->
|
||||
appendSetFixtures($("<script>", {id: "no-textbooks-tpl", type: "text/template"}).text(noTextbooksTpl))
|
||||
appendSetFixtures($("<script>", {id: "edit-textbook-tpl", type: "text/template"}).text(editTextbooktpl))
|
||||
@collection = new TextbookSet
|
||||
@view = new ListTextbooks({collection: @collection})
|
||||
@view.render()
|
||||
beforeEach(function() {
|
||||
appendSetFixtures($("<script>", {id: "no-textbooks-tpl", type: "text/template"}).text(noTextbooksTpl));
|
||||
appendSetFixtures($("<script>", {id: "edit-textbook-tpl", type: "text/template"}).text(editTextbooktpl));
|
||||
this.collection = new TextbookSet;
|
||||
this.view = new ListTextbooks({collection: this.collection});
|
||||
return this.view.render();
|
||||
});
|
||||
|
||||
it "should scroll to newly added textbook", ->
|
||||
spyOn(ViewUtils, 'setScrollOffset')
|
||||
@view.$(".new-button").click()
|
||||
$sectionEl = @view.$el.find('section:last')
|
||||
expect($sectionEl.length).toEqual(1)
|
||||
expect(ViewUtils.setScrollOffset).toHaveBeenCalledWith($sectionEl, 0)
|
||||
it("should scroll to newly added textbook", function() {
|
||||
spyOn(ViewUtils, 'setScrollOffset');
|
||||
this.view.$(".new-button").click();
|
||||
const $sectionEl = this.view.$el.find('section:last');
|
||||
expect($sectionEl.length).toEqual(1);
|
||||
return expect(ViewUtils.setScrollOffset).toHaveBeenCalledWith($sectionEl, 0);
|
||||
});
|
||||
|
||||
it "should focus first input element of newly added textbook", ->
|
||||
spyOn(jQuery.fn, 'focus').and.callThrough()
|
||||
jasmine.addMatchers
|
||||
toHaveBeenCalledOnJQueryObject: () ->
|
||||
return it("should focus first input element of newly added textbook", function() {
|
||||
spyOn(jQuery.fn, 'focus').and.callThrough();
|
||||
jasmine.addMatchers({
|
||||
toHaveBeenCalledOnJQueryObject() {
|
||||
return {
|
||||
compare: (actual, expected) ->
|
||||
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)
|
||||
# testing for element focused seems to be tricky
|
||||
# (see http://stackoverflow.com/questions/967096)
|
||||
# and the following doesn't seem to work
|
||||
# expect($inputEl).toBeFocused()
|
||||
# expect($inputEl.find(':focus').length).toEqual(1)
|
||||
expect(jQuery.fn.focus).toHaveBeenCalledOnJQueryObject($inputEl)
|
||||
(actual.calls.mostRecent().object[0] === expected[0])
|
||||
};
|
||||
}
|
||||
};
|
||||
}});
|
||||
this.view.$(".new-button").click();
|
||||
const $inputEl = this.view.$el.find('section:last input:first');
|
||||
expect($inputEl.length).toEqual(1);
|
||||
// testing for element focused seems to be tricky
|
||||
// (see http://stackoverflow.com/questions/967096)
|
||||
// and the following doesn't seem to work
|
||||
// expect($inputEl).toBeFocused()
|
||||
// expect($inputEl.find(':focus').length).toEqual(1)
|
||||
return expect(jQuery.fn.focus).toHaveBeenCalledOnJQueryObject($inputEl);
|
||||
});
|
||||
});
|
||||
|
||||
# describe "ListTextbooks", ->
|
||||
# noTextbooksTpl = readFixtures("no-textbooks.underscore")
|
||||
#
|
||||
# beforeEach ->
|
||||
# setFixtures($("<script>", {id: "no-textbooks-tpl", type: "text/template"}).text(noTextbooksTpl))
|
||||
# @showSpies = spyOnConstructor("ShowTextbook", ["render"])
|
||||
# @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.and.returnValue(@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 "ListTextbooks", ->
|
||||
// noTextbooksTpl = readFixtures("no-textbooks.underscore")
|
||||
//
|
||||
// beforeEach ->
|
||||
// setFixtures($("<script>", {id: "no-textbooks-tpl", type: "text/template"}).text(noTextbooksTpl))
|
||||
// @showSpies = spyOnConstructor("ShowTextbook", ["render"])
|
||||
// @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.and.returnValue(@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", ->
|
||||
beforeEach ->
|
||||
modal_helpers.installModalTemplates()
|
||||
@model = new Chapter
|
||||
name: "Chapter 1"
|
||||
return describe("EditChapter", function() {
|
||||
beforeEach(function() {
|
||||
modal_helpers.installModalTemplates();
|
||||
this.model = new Chapter({
|
||||
name: "Chapter 1",
|
||||
asset_path: "/ch1.pdf"
|
||||
@collection = new ChapterSet()
|
||||
@collection.add(@model)
|
||||
@view = new EditChapter({model: @model})
|
||||
spyOn(@view, "remove").and.callThrough()
|
||||
CMS.URL.UPLOAD_ASSET = "/upload"
|
||||
window.course = new Course({name: "abcde"})
|
||||
});
|
||||
this.collection = new ChapterSet();
|
||||
this.collection.add(this.model);
|
||||
this.view = new EditChapter({model: this.model});
|
||||
spyOn(this.view, "remove").and.callThrough();
|
||||
CMS.URL.UPLOAD_ASSET = "/upload";
|
||||
return window.course = new Course({name: "abcde"});
|
||||
});
|
||||
|
||||
afterEach ->
|
||||
delete CMS.URL.UPLOAD_ASSET
|
||||
delete window.course
|
||||
afterEach(function() {
|
||||
delete CMS.URL.UPLOAD_ASSET;
|
||||
return delete window.course;
|
||||
});
|
||||
|
||||
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 render", function() {
|
||||
this.view.render();
|
||||
expect(this.view.$("input.chapter-name").val()).toEqual("Chapter 1");
|
||||
return expect(this.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 delete itself", function() {
|
||||
this.view.render().$(".action-close").click();
|
||||
expect(this.collection.length).toEqual(0);
|
||||
return expect(this.view.remove).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
# it "can open an upload dialog", ->
|
||||
# uploadSpies = spyOnConstructor("UploadDialog", ["show", "el"])
|
||||
# uploadSpies.show.and.returnValue(uploadSpies)
|
||||
#
|
||||
# @view.render().$(".action-upload").click()
|
||||
# ctorOptions = uploadSpies.constructor.calls.mostRecent().args[0]
|
||||
# expect(ctorOptions.model.get('title')).toMatch(/abcde/)
|
||||
# expect(typeof ctorOptions.onSuccess).toBe('function')
|
||||
# expect(uploadSpies.show).toHaveBeenCalled()
|
||||
// it "can open an upload dialog", ->
|
||||
// uploadSpies = spyOnConstructor("UploadDialog", ["show", "el"])
|
||||
// uploadSpies.show.and.returnValue(uploadSpies)
|
||||
//
|
||||
// @view.render().$(".action-upload").click()
|
||||
// ctorOptions = uploadSpies.constructor.calls.mostRecent().args[0]
|
||||
// expect(ctorOptions.model.get('title')).toMatch(/abcde/)
|
||||
// expect(typeof ctorOptions.onSuccess).toBe('function')
|
||||
// expect(uploadSpies.show).toHaveBeenCalled()
|
||||
|
||||
# Disabling because this test does not close the modal dialog. This can cause
|
||||
# tests that run after it to fail (see STUD-1963).
|
||||
xit "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")
|
||||
// Disabling because this test does not close the modal dialog. This can cause
|
||||
// tests that run after it to fail (see STUD-1963).
|
||||
return xit("saves content when opening upload dialog", function() {
|
||||
this.view.render();
|
||||
this.view.$("input.chapter-name").val("rainbows");
|
||||
this.view.$("input.chapter-asset-path").val("unicorns");
|
||||
this.view.$(".action-upload").click();
|
||||
expect(this.model.get("name")).toEqual("rainbows");
|
||||
return expect(this.model.get("asset_path")).toEqual("unicorns");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,135 +1,161 @@
|
||||
define ["sinon", "js/models/uploads", "js/views/uploads", "js/models/chapter",
|
||||
/*
|
||||
* decaffeinate suggestions:
|
||||
* DS102: Remove unnecessary code created because of implicit returns
|
||||
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||
*/
|
||||
define(["sinon", "js/models/uploads", "js/views/uploads", "js/models/chapter",
|
||||
"edx-ui-toolkit/js/utils/spec-helpers/ajax-helpers", "js/spec_helpers/modal_helpers"],
|
||||
(sinon, FileUpload, UploadDialog, Chapter, AjaxHelpers, modal_helpers) ->
|
||||
(sinon, FileUpload, UploadDialog, Chapter, AjaxHelpers, modal_helpers) =>
|
||||
|
||||
describe "UploadDialog", ->
|
||||
tpl = readFixtures("upload-dialog.underscore")
|
||||
describe("UploadDialog", function() {
|
||||
const tpl = readFixtures("upload-dialog.underscore");
|
||||
|
||||
beforeEach ->
|
||||
modal_helpers.installModalTemplates()
|
||||
appendSetFixtures($("<script>", {id: "upload-dialog-tpl", type: "text/template"}).text(tpl))
|
||||
CMS.URL.UPLOAD_ASSET = "/upload"
|
||||
@model = new FileUpload(
|
||||
beforeEach(function() {
|
||||
let dialogResponse;
|
||||
modal_helpers.installModalTemplates();
|
||||
appendSetFixtures($("<script>", {id: "upload-dialog-tpl", type: "text/template"}).text(tpl));
|
||||
CMS.URL.UPLOAD_ASSET = "/upload";
|
||||
this.model = new FileUpload({
|
||||
mimeTypes: ['application/pdf']
|
||||
)
|
||||
@dialogResponse = dialogResponse = []
|
||||
@mockFiles = []
|
||||
});
|
||||
this.dialogResponse = (dialogResponse = []);
|
||||
return this.mockFiles = [];});
|
||||
|
||||
afterEach ->
|
||||
delete CMS.URL.UPLOAD_ASSET
|
||||
modal_helpers.cancelModalIfShowing()
|
||||
afterEach(function() {
|
||||
delete CMS.URL.UPLOAD_ASSET;
|
||||
return modal_helpers.cancelModalIfShowing();
|
||||
});
|
||||
|
||||
createTestView = (test) ->
|
||||
view = new UploadDialog(
|
||||
const createTestView = function(test) {
|
||||
const view = new UploadDialog({
|
||||
model: test.model,
|
||||
url: CMS.URL.UPLOAD_ASSET,
|
||||
onSuccess: (response) =>
|
||||
test.dialogResponse.push(response.response)
|
||||
)
|
||||
spyOn(view, 'remove').and.callThrough()
|
||||
onSuccess: response => {
|
||||
return test.dialogResponse.push(response.response);
|
||||
}
|
||||
});
|
||||
spyOn(view, 'remove').and.callThrough();
|
||||
|
||||
# create mock file input, so that we aren't subject to browser restrictions
|
||||
mockFileInput = jasmine.createSpy('mockFileInput')
|
||||
mockFileInput.files = test.mockFiles
|
||||
jqMockFileInput = jasmine.createSpyObj('jqMockFileInput', ['get', 'replaceWith'])
|
||||
jqMockFileInput.get.and.returnValue(mockFileInput)
|
||||
originalView$ = view.$
|
||||
spyOn(view, "$").and.callFake (selector) ->
|
||||
if selector == "input[type=file]"
|
||||
jqMockFileInput
|
||||
else
|
||||
originalView$.apply(this, arguments)
|
||||
@lastView = view
|
||||
// create mock file input, so that we aren't subject to browser restrictions
|
||||
const mockFileInput = jasmine.createSpy('mockFileInput');
|
||||
mockFileInput.files = test.mockFiles;
|
||||
const jqMockFileInput = jasmine.createSpyObj('jqMockFileInput', ['get', 'replaceWith']);
|
||||
jqMockFileInput.get.and.returnValue(mockFileInput);
|
||||
const originalView$ = view.$;
|
||||
spyOn(view, "$").and.callFake(function(selector) {
|
||||
if (selector === "input[type=file]") {
|
||||
return jqMockFileInput;
|
||||
} else {
|
||||
return originalView$.apply(this, arguments);
|
||||
}
|
||||
});
|
||||
return this.lastView = view;
|
||||
};
|
||||
|
||||
describe "Basic", ->
|
||||
it "should render without a file selected", ->
|
||||
view = createTestView(this)
|
||||
view.render()
|
||||
expect(view.$el).toContainElement("input[type=file]")
|
||||
expect(view.$(".action-upload")).toHaveClass("disabled")
|
||||
describe("Basic", function() {
|
||||
it("should render without a file selected", function() {
|
||||
const view = createTestView(this);
|
||||
view.render();
|
||||
expect(view.$el).toContainElement("input[type=file]");
|
||||
return expect(view.$(".action-upload")).toHaveClass("disabled");
|
||||
});
|
||||
|
||||
it "should render with a PDF selected", ->
|
||||
view = createTestView(this)
|
||||
file = {name: "fake.pdf", "type": "application/pdf"}
|
||||
@mockFiles.push(file)
|
||||
@model.set("selectedFile", file)
|
||||
view.render()
|
||||
expect(view.$el).toContainElement("input[type=file]")
|
||||
expect(view.$el).not.toContainElement("#upload_error")
|
||||
expect(view.$(".action-upload")).not.toHaveClass("disabled")
|
||||
it("should render with a PDF selected", function() {
|
||||
const view = createTestView(this);
|
||||
const file = {name: "fake.pdf", "type": "application/pdf"};
|
||||
this.mockFiles.push(file);
|
||||
this.model.set("selectedFile", file);
|
||||
view.render();
|
||||
expect(view.$el).toContainElement("input[type=file]");
|
||||
expect(view.$el).not.toContainElement("#upload_error");
|
||||
return expect(view.$(".action-upload")).not.toHaveClass("disabled");
|
||||
});
|
||||
|
||||
it "should render an error with an invalid file type selected", ->
|
||||
view = createTestView(this)
|
||||
file = {name: "fake.png", "type": "image/png"}
|
||||
@mockFiles.push(file)
|
||||
@model.set("selectedFile", file)
|
||||
view.render()
|
||||
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 selected", function() {
|
||||
const view = createTestView(this);
|
||||
const file = {name: "fake.png", "type": "image/png"};
|
||||
this.mockFiles.push(file);
|
||||
this.model.set("selectedFile", file);
|
||||
view.render();
|
||||
expect(view.$el).toContainElement("input[type=file]");
|
||||
expect(view.$el).toContainElement("#upload_error");
|
||||
return expect(view.$(".action-upload")).toHaveClass("disabled");
|
||||
});
|
||||
|
||||
it "should render an error with an invalid file type after a correct file type selected", ->
|
||||
view = createTestView(this)
|
||||
correctFile = {name: "fake.pdf", "type": "application/pdf"}
|
||||
inCorrectFile = {name: "fake.png", "type": "image/png"}
|
||||
event = {}
|
||||
view.render()
|
||||
return it("should render an error with an invalid file type after a correct file type selected", function() {
|
||||
const view = createTestView(this);
|
||||
const correctFile = {name: "fake.pdf", "type": "application/pdf"};
|
||||
const inCorrectFile = {name: "fake.png", "type": "image/png"};
|
||||
const event = {};
|
||||
view.render();
|
||||
|
||||
event.target = {"files": [correctFile]}
|
||||
view.selectFile(event)
|
||||
expect(view.$el).toContainElement("input[type=file]")
|
||||
expect(view.$el).not.toContainElement("#upload_error")
|
||||
expect(view.$(".action-upload")).not.toHaveClass("disabled")
|
||||
event.target = {"files": [correctFile]};
|
||||
view.selectFile(event);
|
||||
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").and.callFake (data) ->
|
||||
if data.selectedFile != undefined
|
||||
this.attributes.selectedFile = data.selectedFile
|
||||
this.changed = {}
|
||||
else
|
||||
realMethod.apply(this, arguments)
|
||||
const realMethod = this.model.set;
|
||||
spyOn(this.model, "set").and.callFake(function(data) {
|
||||
if (data.selectedFile !== undefined) {
|
||||
this.attributes.selectedFile = data.selectedFile;
|
||||
return this.changed = {};
|
||||
} else {
|
||||
return realMethod.apply(this, arguments);
|
||||
}
|
||||
});
|
||||
|
||||
event.target = {"files": [inCorrectFile]}
|
||||
view.selectFile(event)
|
||||
expect(view.$el).toContainElement("input[type=file]")
|
||||
expect(view.$el).toContainElement("#upload_error")
|
||||
expect(view.$(".action-upload")).toHaveClass("disabled")
|
||||
event.target = {"files": [inCorrectFile]};
|
||||
view.selectFile(event);
|
||||
expect(view.$el).toContainElement("input[type=file]");
|
||||
expect(view.$el).toContainElement("#upload_error");
|
||||
return expect(view.$(".action-upload")).toHaveClass("disabled");
|
||||
});
|
||||
});
|
||||
|
||||
describe "Uploads", ->
|
||||
beforeEach ->
|
||||
@clock = sinon.useFakeTimers()
|
||||
return describe("Uploads", function() {
|
||||
beforeEach(function() {
|
||||
return this.clock = sinon.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach ->
|
||||
modal_helpers.cancelModalIfShowing()
|
||||
@clock.restore()
|
||||
afterEach(function() {
|
||||
modal_helpers.cancelModalIfShowing();
|
||||
return this.clock.restore();
|
||||
});
|
||||
|
||||
it "can upload correctly", ->
|
||||
requests = AjaxHelpers.requests(this);
|
||||
view = createTestView(this)
|
||||
view.render()
|
||||
view.upload()
|
||||
expect(@model.get("uploading")).toBeTruthy()
|
||||
AjaxHelpers.expectRequest(requests, "POST", "/upload")
|
||||
AjaxHelpers.respondWithJson(requests, { response: "dummy_response"})
|
||||
expect(@model.get("uploading")).toBeFalsy()
|
||||
expect(@model.get("finished")).toBeTruthy()
|
||||
expect(@dialogResponse.pop()).toEqual("dummy_response")
|
||||
it("can upload correctly", function() {
|
||||
const requests = AjaxHelpers.requests(this);
|
||||
const view = createTestView(this);
|
||||
view.render();
|
||||
view.upload();
|
||||
expect(this.model.get("uploading")).toBeTruthy();
|
||||
AjaxHelpers.expectRequest(requests, "POST", "/upload");
|
||||
AjaxHelpers.respondWithJson(requests, { response: "dummy_response"});
|
||||
expect(this.model.get("uploading")).toBeFalsy();
|
||||
expect(this.model.get("finished")).toBeTruthy();
|
||||
return expect(this.dialogResponse.pop()).toEqual("dummy_response");
|
||||
});
|
||||
|
||||
it "can handle upload errors", ->
|
||||
requests = AjaxHelpers.requests(this);
|
||||
view = createTestView(this)
|
||||
view.render()
|
||||
view.upload()
|
||||
AjaxHelpers.respondWithError(requests)
|
||||
expect(@model.get("title")).toMatch(/error/)
|
||||
expect(view.remove).not.toHaveBeenCalled()
|
||||
it("can handle upload errors", function() {
|
||||
const requests = AjaxHelpers.requests(this);
|
||||
const view = createTestView(this);
|
||||
view.render();
|
||||
view.upload();
|
||||
AjaxHelpers.respondWithError(requests);
|
||||
expect(this.model.get("title")).toMatch(/error/);
|
||||
return expect(view.remove).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it "removes itself after two seconds on successful upload", ->
|
||||
requests = AjaxHelpers.requests(this);
|
||||
view = createTestView(this)
|
||||
view.render()
|
||||
view.upload()
|
||||
AjaxHelpers.respondWithJson(requests, { response: "dummy_response"})
|
||||
return it("removes itself after two seconds on successful upload", function() {
|
||||
const requests = AjaxHelpers.requests(this);
|
||||
const view = createTestView(this);
|
||||
view.render();
|
||||
view.upload();
|
||||
AjaxHelpers.respondWithJson(requests, { response: "dummy_response"});
|
||||
expect(modal_helpers.isShowingModal(view)).toBeTruthy();
|
||||
@clock.tick(2001)
|
||||
expect(modal_helpers.isShowingModal(view)).toBeFalsy();
|
||||
this.clock.tick(2001);
|
||||
return expect(modal_helpers.isShowingModal(view)).toBeFalsy();
|
||||
});
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user