Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { createConfig } = require('@edx/frontend-build');
const { createConfig } = require('@openedx/frontend-build');

const config = createConfig('eslint');

Expand Down
2 changes: 1 addition & 1 deletion babel.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
const { createConfig } = require('@edx/frontend-build');
const { createConfig } = require('@openedx/frontend-build');

module.exports = createConfig('babel');
2 changes: 2 additions & 0 deletions karma.conf.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// Karma configuration
process.env.NODE_ENV = 'dev';

const webpackConfig = require('./webpack.prod.config.js');

module.exports = function(config) {
Expand Down
75 changes: 44 additions & 31 deletions openassessment/xblock/static/js/spec/lms/oa_response.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,36 +186,51 @@ describe("OpenAssessment.ResponseView", function() {
var rootElement = $('.step--response').parent().get(0);
var baseView = new BaseView(runtime, rootElement, server, data);
view = new ResponseView(rootElement, server, fileUploader, baseView.responseEditorLoader, baseView, data);
view.loadResponseEditor().then(editorCtrl => {
view.responseEditorController = editorCtrl
view.installHandlers()

// Stub the confirmation step
// By default, we simulate the user confirming the submission.
// To instead simulate the user cancelling the submission,
// set `stubConfirm` to false.
setStubConfirm(true);
const fakeConfirm = function(_0, _1, confirmCallback, cancelCallback) {
if (stubConfirm) {
confirmCallback();
} else {
cancelCallback();
var mockEditorController = {
_response: ['', ''],
load: function(elements) {
this.elements = elements;
return Promise.resolve();
},
response: function(texts) {
if (typeof texts !== 'undefined') {
this._response = texts;
return this._response;
}
return this._response;
},
setOnChangeListener: function(callback) {
this._changeCallback = callback;
}
spyOn(view.confirmationDialog, 'confirm').and.callFake(fakeConfirm);
spyOn(view, 'saveFilesDescriptions').and.callFake(function() {
for (var i=0; i < this.filesDescriptions.length; i++) {
this.fileNames.push(this.files[i].name);
}
return $.Deferred(function(defer) {
view.removeFilesDescriptions();
defer.resolve();
});
};
view.responseEditorController = mockEditorController;
view.installHandlers();

// Stub the confirmation step
// By default, we simulate the user confirming the submission.
// To instead simulate the user cancelling the submission,
// set `stubConfirm` to false.
setStubConfirm(true);
const fakeConfirm = function(_0, _1, confirmCallback, cancelCallback) {
if (stubConfirm) {
confirmCallback();
} else {
cancelCallback();
}
};
spyOn(view.confirmationDialog, 'confirm').and.callFake(fakeConfirm);
spyOn(view, 'saveFilesDescriptions').and.callFake(function() {
for (var i=0; i < this.filesDescriptions.length; i++) {
this.fileNames.push(this.files[i].name);
}
return $.Deferred(function(defer) {
view.removeFilesDescriptions();
defer.resolve();
});
window.URL = mockURL;
});
window.URL = mockURL;

done()
})
done();
});

afterEach(function() {
Expand All @@ -236,19 +251,17 @@ describe("OpenAssessment.ResponseView", function() {

describe('is valid for submission', function() {
it('response require text', function() {
// response is blank
view.response(['', '']);
view.handleResponseChanged();
// Initial state - response is blank and should not be saved
expect(view.submitEnabled()).toBe(true);
expect(view.isValidForSubmit()).toBe(false);
expect(view.saveStatus()).toContain('This response has not been saved');

// response is whitespace
// response is whitespace - should trigger saving draft but still be invalid
view.response([' \n \n ', ' ']);
view.handleResponseChanged();
expect(view.submitEnabled()).toBe(true);
expect(view.isValidForSubmit()).toBe(false);
expect(view.saveStatus()).toContain('This response has not been saved');
expect(view.saveStatus()).toContain('Saving draft');

// response is not blank
view.response(['Test response 1', ' ']);
Expand Down
124 changes: 81 additions & 43 deletions openassessment/xblock/static/js/spec/lms/oa_response_editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,69 +20,107 @@ describe("OpenAssessment.ResponseEditorLoader", function () {

let response = 'generic response'

describe('Simple text editor', () => {
describe('Simple text editor', () => {
let loader;
let originalRequire;
beforeEach(() => {
originalRequire = window.require;
window.require = function(modules, callback) {
const MockEditorTextarea = function() {
return {
elements: null,
load: function(elements) {
this.elements = elements;
return Promise.resolve();
},
response: function(texts) {
if (typeof texts !== 'undefined') {
this._response = texts;
return this._response;
}
return this._response || [];
},
setOnChangeListener: function(callback) {
this._changeCallback = callback;
}
};
};
setTimeout(() => callback(MockEditorTextarea), 0);
};
loader = new ResponseEditorLoader(availableEditors);
});
afterEach(() => {
window.require = originalRequire;
});

it('Loads text editor js and css properly', function (done) {
let loader = new ResponseEditorLoader(availableEditors)
let elements = $('textarea')

let elements = $('textarea');

loader.load('text', elements).then(editor => {

// editor is an instance of oa_editor_textarea
// it should have `elements` property set to given one
expect(editor.elements).toBe(elements)
expect(editor.elements).toBe(elements);

// css file should also be included
expect($(`link[href='${cssFile}']`).length).toBe(1)
done()
})
})
expect($(`link[href='${cssFile}']`).length).toBe(1);
done();
});
});

it('Text area editor get instantiated properly', function(done) {
let loader = new ResponseEditorLoader(availableEditors)
let elements = $('textarea')
let elements = $('textarea');
loader.load('text', elements).then(editor => {
editor.response([response])
expect(editor.response(), response)
done()
editor.response([response]);
expect(editor.response()).toEqual([response]);
done();
});
})
});
})

describe('WYSIWYG text editor', () => {
let loader = new ResponseEditorLoader(availableEditors)
let elements = $('textarea')

let editorStub = (elements) => ({
elements,
response: () => response
})
let loader;
let elements;
let originalRequire;

beforeEach(() => {
loader = new ResponseEditorLoader(availableEditors)
elements = $('textarea')

spyOn(loader, 'load').and.callFake(function(selectedEditor, elements){
return new Promise(resolve => {
setTimeout(() => resolve(editorStub(elements)), 500)
})
})
})

originalRequire = window.require;
window.require = function(modules, callback) {
const MockEditorTinyMCE = function() {
return {
elements: null,
load: function(elements) {
this.elements = elements;
return Promise.resolve();
},
response: function() {
return response;
}
};
};
setTimeout(() => callback(MockEditorTinyMCE), 0);
};
loader = new ResponseEditorLoader(availableEditors);
elements = $('textarea');
});
afterEach(() => {
window.require = originalRequire;
});

it('Loads tinymce editor js and css properly', function (done) {
loader.load('tinymce', elements).then(editor => {
// editor is an instance of oa_editor_tinymce
// it should have `elements` property set to given one
expect(editor.elements).toBe(elements)
done()
})
})
it('TinyMCE editor get instantiated properly', async function(done) {
expect(editor.elements).toBe(elements);
done();
});
});

it('TinyMCE editor get instantiated properly', function(done) {
loader.load('tinymce', elements).then(editor => {
// editor should have response even after the delay
expect(editor.response(), response)
done()
expect(editor.response()).toBe(response);
done();
});
})
});
})
})
27 changes: 22 additions & 5 deletions openassessment/xblock/static/js/spec/lms/oa_self.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,28 @@ describe("OpenAssessment.SelfView", function() {
}
}
});
view = baseView.selfView
view.renderResponseViaEditor().then(() => {
view.installHandlers();
done()
});
view = baseView.selfView;
var mockEditorController = {
_response: [],
load: function(elements) {
this.elements = elements;
return Promise.resolve();
},
response: function(texts) {
if (typeof texts !== 'undefined') {
this._response = texts;
return this._response;
}
return this._response;
},
setOnChangeListener: function(callback) {
this._changeCallback = callback;
}
};

view.responseEditorController = mockEditorController;
view.installHandlers();
done();
});

afterEach(function() {
Expand Down
32 changes: 28 additions & 4 deletions openassessment/xblock/static/js/spec/lms/oa_training.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ describe("OpenAssessment.StudentTrainingView", function() {

// Create a new stub server
server = new StubServer();
server.renderLatex = jasmine.createSpy('renderLatex')
server.renderLatex = jasmine.createSpy('renderLatex');

// Create the object under test
var rootElement = $('.step--student-training').parent().get(0);
Expand All @@ -55,11 +55,35 @@ describe("OpenAssessment.StudentTrainingView", function() {
}
}
});
view = baseView.trainingView
view = baseView.trainingView;

// Create a mock editor controller to avoid RequireJS loading issues in tests
var mockEditorController = {
_response: ['', ''],
load: function(elements) {
this.elements = elements;
return Promise.resolve();
},
response: function(texts) {
if (typeof texts !== 'undefined') {
this._response = texts;
return this._response;
}
return this._response;
},
setOnChangeListener: function(callback) {
this._changeCallback = callback;
}
};

// Mock the responseEditorLoader to avoid async loading issues
spyOn(view.responseEditorLoader, 'load').and.returnValue(Promise.resolve(mockEditorController));

// Now call renderResponseViaEditor and installHandlers
view.renderResponseViaEditor().then(() => {
view.installHandlers();
done()
})
done();
});
});

it("submits an assessment for a training example", function() {
Expand Down
Loading