Commit 39e97225 by polesye

Fix tests.

parent 2e87b1a6
/**
* File: constructor.js
*
* Purpose: Jasmine tests for LTI module (front-end part).
*
*
* Because LTI module is constructed so that all methods are available via the
* prototype chain, many times we can test methods without having to
* instantiate a new LTI object.
*/
/*
* "Hence that general is skillful in attack whose opponent does not know what
* to defend; and he is skillful in defense whose opponent does not know what
* to attack."
*
* ~ Sun Tzu
*/
(function () {
var IN_NEW_WINDOW = 'true',
IN_IFRAME = 'false',
EMPTY_URL = '',
DEFAULT_URL = 'http://www.example.com',
NEW_URL = 'http://www.example.com/some_book';
describe('LTI XModule', function () {
describe('LTIConstructor method', function () {
describe('[in iframe, new url]', function () {
var lti;
beforeEach(function () {
loadFixtures('lti.html');
setUpLtiElement($('.lti-wrapper'), IN_IFRAME, NEW_URL);
spyOnEvent(
$('.lti-wrapper').find('.ltiLaunchForm'), 'submit'
);
lti = new window.LTI('.lti-wrapper');
});
it('new LTI object contains all properties', function () {
expect(lti.el).toBeDefined();
expect(lti.el).toExist();
expect(lti.formEl).toBeDefined();
expect(lti.formEl).toExist();
expect(lti.formEl).toHaveAttr('action');
expect(lti.ltiEl).toBeDefined();
expect(lti.ltiEl).toExist();
expect(lti.formAction).toEqual(NEW_URL);
expect(lti.openInANewPage).toEqual(false);
expect(lti.ajaxUrl).toEqual(jasmine.any(String));
expect('submit').toHaveBeenTriggeredOn(lti.formEl);
});
afterEach(function () {
lti = undefined;
});
});
describe('[in new window, new url]', function () {
var lti;
beforeEach(function () {
loadFixtures('lti.html');
setUpLtiElement($('.lti-wrapper'), IN_NEW_WINDOW, NEW_URL);
lti = new window.LTI('.lti-wrapper');
});
it('check extra properties and values', function () {
expect(lti.openInANewPage).toEqual(true);
expect(lti.signatureIsNew).toBeTruthy();
expect(lti.newWindowBtnEl).toBeDefined();
expect(lti.newWindowBtnEl).toExist();
expect(lti.disableOpenNewWindowBtn).toBe(false);
});
afterEach(function () {
lti = undefined;
});
});
describe('[in iframe, NO new url]', function () {
var testCases = [{
itDescription: 'URL is blank',
action: EMPTY_URL
}, {
itDescription: 'URL is default',
action: DEFAULT_URL
}];
$.each(testCases, function (index, test) {
it(test.itDescription, function () {
var lti;
loadFixtures('lti.html');
setUpLtiElement(
$('.lti-wrapper'), IN_IFRAME, test.action
);
lti = new window.LTI('.lti-wrapper');
expect(lti.openInANewPage).not.toBeDefined();
});
});
});
});
describe('submitFormHandler method', function () {
var thisObj;
beforeEach(function () {
thisObj = {
signatureIsNew: undefined,
getNewSignature: jasmine.createSpy('getNewSignature'),
formEl: {
submit: jasmine.createSpy('submit')
}
};
});
it('signature is new', function () {
thisObj.signatureIsNew = true;
window.LTI.prototype.submitFormHandler.call(thisObj);
expect(thisObj.formEl.submit).toHaveBeenCalled();
expect(thisObj.signatureIsNew).toBe(false);
});
it('signature is old', function () {
thisObj.signatureIsNew = false;
window.LTI.prototype.submitFormHandler.call(thisObj);
expect(thisObj.formEl.submit).not.toHaveBeenCalled();
expect(thisObj.signatureIsNew).toBe(false);
expect(thisObj.getNewSignature).toHaveBeenCalled();
});
afterEach(function () {
thisObj = undefined;
});
});
describe('getNewSignature method', function () {
var lti;
beforeEach(function () {
loadFixtures('lti.html');
setUpLtiElement($('.lti-wrapper'), IN_NEW_WINDOW, NEW_URL);
spyOn($, 'postWithPrefix').andCallFake(
function (url, data, callback) {
callback({
input_fields: {}
});
}
);
lti = new window.LTI('.lti-wrapper');
spyOn(lti, 'submitFormHandler').andCallThrough();
lti.submitFormHandler.reset();
spyOn(lti, 'handleAjaxUpdateSignature');
});
it(
'"Open in new page" clicked twice, signature requested once',
function () {
lti.newWindowBtnEl.click();
lti.newWindowBtnEl.click();
expect(lti.submitFormHandler).toHaveBeenCalled();
expect(lti.submitFormHandler.callCount).toBe(2);
expect($.postWithPrefix).toHaveBeenCalledWith(
lti.ajaxUrl + '/regenerate_signature',
{},
jasmine.any(Function)
);
expect(lti.disableOpenNewWindowBtn).toBe(true);
expect(lti.handleAjaxUpdateSignature)
.toHaveBeenCalledWith({
input_fields: {}
});
}
);
afterEach(function () {
lti = undefined;
});
});
describe('handleAjaxUpdateSignature method', function () {
var lti, oldInputFields, newInputFields,
AjaxCallbackData = {};
function fakePostWithPrefix(url, data, callback) {
return callback(AjaxCallbackData);
}
beforeEach(function () {
oldInputFields = {
oauth_nonce: '28347958723982798572',
oauth_timestamp: '2389479832',
oauth_signature: '89ru3289r3ry283y3r82ryr38yr'
};
newInputFields = {
oauth_nonce: 'ru3902ru239ru',
oauth_timestamp: '24ru309rur39r8u',
oauth_signature: '08923ru3082u2rur'
};
AjaxCallbackData.error = 0;
AjaxCallbackData.input_fields = newInputFields;
loadFixtures('lti.html');
setUpLtiElement($('.lti-wrapper'), IN_NEW_WINDOW, NEW_URL);
spyOn($, 'postWithPrefix').andCallFake(fakePostWithPrefix);
lti = new window.LTI('.lti-wrapper');
spyOn(lti, 'submitFormHandler').andCallThrough();
spyOn(lti, 'handleAjaxUpdateSignature').andCallThrough();
spyOn(lti.formEl, 'submit');
spyOn(window.console, 'log').andCallThrough();
lti.submitFormHandler.reset();
lti.handleAjaxUpdateSignature.reset();
lti.formEl.submit.reset();
window.console.log.reset();
});
it('On second click form is updated, and submitted', function () {
// Setup initial OAuth values in the form.
lti.formEl.find("input[name='oauth_nonce']")
.val(oldInputFields.oauth_nonce);
lti.formEl.find("input[name='oauth_timestamp']")
.val(oldInputFields.oauth_timestamp);
lti.formEl.find("input[name='oauth_signature']")
.val(oldInputFields.oauth_signature);
// First click. Signature is new. Should just submit the form.
lti.newWindowBtnEl.click();
// Initial OAuth values should not have changed.
expect(lti.formEl.find("input[name='oauth_nonce']").val())
.toBe(oldInputFields.oauth_nonce);
expect(lti.formEl.find("input[name='oauth_timestamp']").val())
.toBe(oldInputFields.oauth_timestamp);
expect(lti.formEl.find("input[name='oauth_signature']").val())
.toBe(oldInputFields.oauth_signature);
expect(lti.submitFormHandler).toHaveBeenCalled();
expect(lti.submitFormHandler.callCount).toBe(1);
expect(lti.handleAjaxUpdateSignature).not.toHaveBeenCalled();
expect(lti.handleAjaxUpdateSignature.callCount).toBe(0);
expect(lti.formEl.submit).toHaveBeenCalled();
expect(lti.formEl.submit.callCount).toBe(1);
lti.submitFormHandler.reset();
lti.handleAjaxUpdateSignature.reset();
lti.formEl.submit.reset();
// Second click. Signature is old. Should request for a new
// signature, and then submit the form.
lti.newWindowBtnEl.click();
expect(lti.submitFormHandler).toHaveBeenCalled();
expect(lti.submitFormHandler.callCount).toBe(2);
expect(lti.handleAjaxUpdateSignature).toHaveBeenCalled();
expect(lti.handleAjaxUpdateSignature.callCount).toBe(1);
expect(lti.formEl.submit).toHaveBeenCalled();
expect(lti.formEl.submit.callCount).toBe(1);
expect(lti.disableOpenNewWindowBtn).toBe(false);
// The new OAuth values should be in the form.
expect(lti.formEl.find("input[name='oauth_nonce']").val())
.toBe(newInputFields.oauth_nonce);
expect(lti.formEl.find("input[name='oauth_timestamp']").val())
.toBe(newInputFields.oauth_timestamp);
expect(lti.formEl.find("input[name='oauth_signature']").val())
.toBe(newInputFields.oauth_signature);
});
it('invalid response for new OAuth signature', function () {
AjaxCallbackData.input_fields = 0;
AjaxCallbackData.error = 'error';
lti.newWindowBtnEl.click();
lti.submitFormHandler.reset();
lti.handleAjaxUpdateSignature.reset();
window.console.log.reset();
lti.formEl.submit.reset();
lti.newWindowBtnEl.click();
expect(lti.submitFormHandler).toHaveBeenCalled();
expect(lti.submitFormHandler.callCount).toBe(1);
expect(lti.handleAjaxUpdateSignature).toHaveBeenCalled();
expect(lti.handleAjaxUpdateSignature.callCount).toBe(1);
expect(window.console.log).toHaveBeenCalledWith(
jasmine.any(String)
);
expect(lti.formEl.submit).not.toHaveBeenCalled();
});
afterEach(function () {
lti = undefined;
oldInputFields = undefined;
newInputFields = undefined;
});
});
});
function setUpLtiElement(element, target, action) {
var container, form;
container = element.find('.lti');
form = container.find('.ltiLaunchForm');
if (target === IN_IFRAME) {
container.data('open_in_a_new_page', 'false');
form.attr('target', 'ltiLaunchFrame');
}
form.attr('action', action);
// If we have a new proper action (non-default), we create either
// a link that will submit the form, or an iframe that will contain
// the answer of auto submitted form.
if (action !== EMPTY_URL && action !== DEFAULT_URL) {
if (target === IN_NEW_WINDOW) {
$('<a />', {
href: '#',
class: 'link_lti_new_window'
}).appendTo(container);
} else {
$('<iframe />', {
name: 'ltiLaunchFrame',
class: 'ltiLaunchFrame',
src: ''
}).appendTo(container);
}
}
}
}());
......@@ -292,21 +292,6 @@ class LTIModule(LTIFields, XModule):
"""
return Response(self.get_form(), content_type='text/html')
def handle_ajax(self, dispatch, __):
"""
Ajax handler.
Args:
dispatch: string request slug
Returns:
json string
"""
if dispatch == 'regenerate_signature':
return json.dumps({ 'input_fields': self.get_input_fields() })
else: # return error message
return json.dumps({ 'error': '[handle_ajax]: Unknown Command!' })
def get_user_id(self):
user_id = self.runtime.anonymous_student_id
assert user_id is not None
......
......@@ -229,6 +229,12 @@ class LTIModuleTest(LogicTest):
real_outcome_service_url = self.xmodule.get_outcome_service_url()
self.assertEqual(real_outcome_service_url, expected_outcome_service_url)
def test_get_form_path(self):
expected_form_path = self.xmodule.runtime.handler_url(self.xmodule, 'preview_handler').rstrip('/?')
real_form_path = self.xmodule.get_form_path()
self.assertEqual(real_form_path, expected_form_path)
def test_resource_link_id(self):
with patch('xmodule.lti_module.LTIModule.id', new_callable=PropertyMock) as mock_id:
mock_id.return_value = self.module_id
......@@ -251,28 +257,6 @@ class LTIModuleTest(LogicTest):
def test_client_key_secret(self):
pass
def test_handle_ajax(self):
dispatch = 'regenerate_signature'
data = ''
self.xmodule.get_input_fields = Mock(return_value={'test_input_field_key': 'test_input_field_value'})
json_dump = self.xmodule.handle_ajax(dispatch, data)
expected_json_dump = '{"input_fields": {"test_input_field_key": "test_input_field_value"}}'
self.assertEqual(
json.loads(json_dump),
json.loads(expected_json_dump)
)
def test_handle_ajax_bad_dispatch(self):
dispatch = 'bad_dispatch'
data = ''
self.xmodule.get_input_fields = Mock(return_value={'test_input_field_key': 'test_input_field_value'})
json_dump = self.xmodule.handle_ajax(dispatch, data)
expected_json_dump = '{"error": "[handle_ajax]: Unknown Command!"}'
self.assertEqual(
json.loads(json_dump),
json.loads(expected_json_dump)
)
def test_max_score(self):
self.xmodule.weight = 100.0
......
......@@ -13,22 +13,22 @@ from courseware.tests.factories import InstructorFactory
@step('I view the LTI and error is shown$')
def lti_is_not_rendered(_step):
# error is shown
assert world.is_css_present('.error_message')
assert world.is_css_present('.error_message', wait_time=0)
# iframe is not presented
assert not world.is_css_present('iframe')
assert not world.is_css_present('iframe', wait_time=0)
# link is not presented
assert not world.is_css_present('.link_lti_new_window')
assert not world.is_css_present('.link_lti_new_window', wait_time=0)
def check_lti_iframe_content(text):
#inside iframe test content is presented
location = world.scenario_dict['LTI'].location.html_id()
iframe_name = 'ltiLaunchFrame-' + location
iframe_name = 'ltiFrame-' + location
with world.browser.get_iframe(iframe_name) as iframe:
# iframe does not contain functions from terrain/ui_helpers.py
assert iframe.is_element_present_by_css('.result', wait_time=5)
assert iframe.is_element_present_by_css('.result', wait_time=0)
assert (text == world.retry_on_exception(
lambda: iframe.find_by_css('.result')[0].text,
max_attempts=5
......@@ -38,18 +38,18 @@ def check_lti_iframe_content(text):
@step('I view the LTI and it is rendered in (.*)$')
def lti_is_rendered(_step, rendered_in):
if rendered_in.strip() == 'iframe':
assert world.is_css_present('iframe')
assert not world.is_css_present('.link_lti_new_window')
assert not world.is_css_present('.error_message')
assert world.is_css_present('iframe', wait_time=2)
assert not world.is_css_present('.link_lti_new_window', wait_time=0)
assert not world.is_css_present('.error_message', wait_time=0)
# iframe is visible
assert world.css_visible('iframe')
check_lti_iframe_content("This is LTI tool. Success.")
elif rendered_in.strip() == 'new page':
assert not world.is_css_present('iframe')
assert world.is_css_present('.link_lti_new_window')
assert not world.is_css_present('.error_message')
assert not world.is_css_present('iframe', wait_time=2)
assert world.is_css_present('.link_lti_new_window', wait_time=0)
assert not world.is_css_present('.error_message', wait_time=0)
check_lti_popup()
else: # incorrent rendered_in parameter
assert False
......@@ -57,9 +57,9 @@ def lti_is_rendered(_step, rendered_in):
@step('I view the LTI but incorrect_signature warning is rendered$')
def incorrect_lti_is_rendered(_step):
assert world.is_css_present('iframe')
assert not world.is_css_present('.link_lti_new_window')
assert not world.is_css_present('.error_message')
assert world.is_css_present('iframe', wait_time=2)
assert not world.is_css_present('.link_lti_new_window', wait_time=0)
assert not world.is_css_present('.error_message', wait_time=0)
#inside iframe test content is presented
check_lti_iframe_content("Wrong LTI signature")
......@@ -234,10 +234,11 @@ def check_progress(_step, text):
@step('I see graph with total progress "([^"]*)"$')
def see_graph(_step, progress):
SELECTOR = 'grade-detail-graph'
node = world.browser.find_by_xpath('//div[@id="{parent}"]//div[text()="{progress}"]'.format(
XPATH = '//div[@id="{parent}"]//div[text()="{progress}"]'.format(
parent=SELECTOR,
progress=progress,
))
)
node = world.browser.find_by_xpath(XPATH)
assert node
......@@ -259,7 +260,7 @@ def see_value_in_the_gradebook(_step, label, text):
@step('I submit answer to LTI question$')
def click_grade(_step):
location = world.scenario_dict['LTI'].location.html_id()
iframe_name = 'ltiLaunchFrame-' + location
iframe_name = 'ltiFrame-' + location
with world.browser.get_iframe(iframe_name) as iframe:
iframe.find_by_name('submit-button').first.click()
assert iframe.is_text_present('LTI consumer (edX) responded with XML content')
......
......@@ -5,8 +5,6 @@ from . import BaseTestXmodule
from collections import OrderedDict
import mock
import urllib
from xmodule.lti_module import LTIModule
from mock import Mock
class TestLTI(BaseTestXmodule):
......@@ -85,7 +83,6 @@ class TestLTI(BaseTestXmodule):
Makes sure that all parameters extracted.
"""
generated_context = self.item_module.render('student_view').content
expected_context = {
'display_name': self.item_module.display_name,
'input_fields': self.correct_headers,
......@@ -93,7 +90,7 @@ class TestLTI(BaseTestXmodule):
'element_id': self.item_module.location.html_id(),
'launch_url': 'http://www.example.com', # default value
'open_in_a_new_page': True,
'ajax_url': self.item_descriptor.xmodule_runtime.ajax_url,
'form_url': self.item_descriptor.xmodule_runtime.handler_url(self.item_module, 'preview_handler').rstrip('/?'),
}
self.assertEqual(
......
......@@ -12,7 +12,7 @@
<h3 class="title">
${display_name} (${_('External resource')})
</h3>
<p class="lti-link external"><a target="_blank" class='link_lti_new_window' href="${form_url}" class=''>
<p class="lti-link external"><a target="_blank" class='link_lti_new_window' href="${form_url}">
${_('View resource in a new window')}
<i class="icon-external-link"></i>
</a></p>
......@@ -21,6 +21,7 @@
## The result of the form submit will be rendered here.
<iframe
class="ltiLaunchFrame"
name="ltiFrame-${element_id}"
src="${form_url}"
></iframe>
% endif
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment