272 lines
12 KiB
JavaScript
272 lines
12 KiB
JavaScript
define([
|
|
'jquery', 'underscore', 'annotator_1.2.9', 'js/edxnotes/views/notes_factory'
|
|
], function($, _, Annotator, NotesFactory) {
|
|
'use strict';
|
|
describe('EdxNotes Shim', function() {
|
|
var annotators, highlights;
|
|
|
|
function checkAnnotatorIsFrozen(annotator) {
|
|
expect(annotator.isFrozen).toBe(true);
|
|
expect(annotator.onHighlightMouseover).not.toHaveBeenCalled();
|
|
expect(annotator.startViewerHideTimer).not.toHaveBeenCalled();
|
|
}
|
|
|
|
function checkAnnotatorIsUnfrozen(annotator) {
|
|
expect(annotator.isFrozen).toBe(false);
|
|
expect(annotator.onHighlightMouseover).toHaveBeenCalled();
|
|
expect(annotator.startViewerHideTimer).toHaveBeenCalled();
|
|
}
|
|
|
|
function checkClickEventsNotBound(namespace) {
|
|
var events = $._data(document, 'events').click;
|
|
|
|
_.each(events, function(event) {
|
|
expect(event.namespace.indexOf(namespace)).toBe(-1);
|
|
});
|
|
}
|
|
|
|
beforeEach(function() {
|
|
loadFixtures('js/fixtures/edxnotes/edxnotes_wrapper.html');
|
|
highlights = [];
|
|
annotators = [
|
|
NotesFactory.factory($('#edx-notes-wrapper-123').get(0), {
|
|
endpoint: 'http://example.com/'
|
|
}),
|
|
NotesFactory.factory($('#edx-notes-wrapper-456').get(0), {
|
|
endpoint: 'http://example.com/'
|
|
})
|
|
];
|
|
_.each(annotators, function(annotator) {
|
|
highlights.push($('<span class="annotator-hl" />').appendTo(annotator.element));
|
|
spyOn(annotator, 'onHighlightClick').and.callThrough();
|
|
spyOn(annotator, 'onHighlightMouseover').and.callThrough();
|
|
spyOn(annotator, 'startViewerHideTimer').and.callThrough();
|
|
});
|
|
spyOn($.fn, 'off').and.callThrough();
|
|
});
|
|
|
|
afterEach(function() {
|
|
while (Annotator._instances.length > 0) {
|
|
Annotator._instances[0].destroy();
|
|
}
|
|
});
|
|
|
|
it('does not show the viewer if the editor is opened', function() {
|
|
annotators[0].showEditor({}, {});
|
|
highlights[0].mouseover();
|
|
expect($('#edx-notes-wrapper-123 .annotator-editor')).not.toHaveClass('annotator-hide');
|
|
expect($('#edx-notes-wrapper-123 .annotator-viewer')).toHaveClass('annotator-hide');
|
|
});
|
|
|
|
it('clicking on highlights does not open the viewer when the editor is opened', function() {
|
|
spyOn(annotators[1].editor, 'isShown').and.returnValue(false);
|
|
highlights[0].click();
|
|
annotators[1].editor.isShown.and.returnValue(true);
|
|
highlights[1].click();
|
|
expect($('#edx-notes-wrapper-123 .annotator-viewer')).not.toHaveClass('annotator-hide');
|
|
expect($('#edx-notes-wrapper-456 .annotator-viewer')).toHaveClass('annotator-hide');
|
|
});
|
|
|
|
it('clicking a highlight freezes mouseover and mouseout in all highlighted text', function() {
|
|
_.each(annotators, function(annotator) {
|
|
expect(annotator.isFrozen).toBe(false);
|
|
});
|
|
highlights[0].click();
|
|
// Click is attached to the onHighlightClick event handler which
|
|
// in turn calls onHighlightMouseover.
|
|
// To test if onHighlightMouseover is called or not on
|
|
// mouseover, we'll have to reset onHighlightMouseover.
|
|
annotators[0].onHighlightMouseover.calls.reset();
|
|
// Check that both instances of annotator are frozen
|
|
_.invoke(highlights, 'mouseover');
|
|
_.invoke(highlights, 'mouseout');
|
|
_.each(annotators, checkAnnotatorIsFrozen);
|
|
});
|
|
|
|
it('clicking twice reverts to default behavior', function() {
|
|
highlights[0].click();
|
|
$(document).click();
|
|
annotators[0].onHighlightMouseover.calls.reset();
|
|
|
|
// Check that both instances of annotator are unfrozen
|
|
_.invoke(highlights, 'mouseover');
|
|
_.invoke(highlights, 'mouseout');
|
|
_.each(annotators, function(annotator) {
|
|
checkAnnotatorIsUnfrozen(annotator);
|
|
});
|
|
});
|
|
|
|
it('destroying an instance with an open viewer sets all other instances' +
|
|
'to unfrozen and unbinds document click.edxnotes:freeze event handlers', function() {
|
|
// Freeze all instances
|
|
highlights[0].click();
|
|
// Destroy first instance
|
|
annotators[0].destroy();
|
|
|
|
// Check that all click.edxnotes:freeze are unbound
|
|
checkClickEventsNotBound('edxnotes:freeze');
|
|
|
|
// Check that the remaining instance is unfrozen
|
|
highlights[1].mouseover();
|
|
highlights[1].mouseout();
|
|
checkAnnotatorIsUnfrozen(annotators[1]);
|
|
});
|
|
|
|
it('destroying an instance with an closed viewer only unfreezes that instance' +
|
|
'and unbinds one document click.edxnotes:freeze event handlers', function() {
|
|
// Freeze all instances
|
|
highlights[0].click();
|
|
annotators[0].onHighlightMouseover.calls.reset();
|
|
// Destroy second instance
|
|
annotators[1].destroy();
|
|
|
|
// Check that the first instance is frozen
|
|
highlights[0].mouseover();
|
|
highlights[0].mouseout();
|
|
checkAnnotatorIsFrozen(annotators[0]);
|
|
|
|
// Check that second one doesn't have a bound click.edxnotes:freeze
|
|
checkClickEventsNotBound('edxnotes:freeze' + annotators[1].uid);
|
|
});
|
|
|
|
it('should unbind events on destruction', function() {
|
|
annotators[0].destroy();
|
|
expect($.fn.off).toHaveBeenCalledWith(
|
|
'click', annotators[0].onNoteClick
|
|
);
|
|
expect($.fn.off).toHaveBeenCalledWith(
|
|
'click', '.annotator-hl'
|
|
);
|
|
});
|
|
|
|
it('should hide viewer when close button is clicked', function() {
|
|
var close,
|
|
annotation = {
|
|
id: '01',
|
|
text: 'Test text',
|
|
highlights: [highlights[0].get(0)]
|
|
};
|
|
|
|
annotators[0].viewer.load([annotation]);
|
|
close = annotators[0].viewer.element.find('.annotator-close');
|
|
close.click();
|
|
expect($('#edx-notes-wrapper-123 .annotator-viewer')).toHaveClass('annotator-hide');
|
|
});
|
|
|
|
describe('_setupViewer', function() {
|
|
var mockViewer = null;
|
|
|
|
beforeEach(function() {
|
|
var $element = $('<div />');
|
|
mockViewer = {
|
|
fields: [],
|
|
element: $element
|
|
};
|
|
|
|
mockViewer.on = jasmine.createSpy().and.returnValue(mockViewer);
|
|
mockViewer.hide = jasmine.createSpy().and.returnValue(mockViewer);
|
|
mockViewer.destroy = jasmine.createSpy().and.returnValue(mockViewer);
|
|
mockViewer.addField = jasmine.createSpy().and.callFake(function(options) {
|
|
mockViewer.fields.push(options);
|
|
return mockViewer;
|
|
});
|
|
|
|
spyOn($element, 'bind').and.returnValue($element);
|
|
spyOn($element, 'appendTo').and.returnValue($element);
|
|
spyOn(Annotator, 'Viewer').and.returnValue(mockViewer);
|
|
|
|
annotators[0]._setupViewer();
|
|
});
|
|
|
|
it('should create a new instance of Annotator.Viewer and set Annotator#viewer', function() {
|
|
expect(annotators[0].viewer).toEqual(mockViewer);
|
|
});
|
|
|
|
it('should hide the annotator on creation', function() {
|
|
expect(mockViewer.hide.calls.count()).toBe(1);
|
|
});
|
|
|
|
it('should setup the default text field', function() {
|
|
var args = mockViewer.addField.calls.mostRecent().args[0];
|
|
|
|
expect(mockViewer.addField.calls.count()).toBe(1);
|
|
expect(_.isFunction(args.load)).toBeTruthy();
|
|
});
|
|
|
|
it('should set the contents of the field on load', function() {
|
|
var field = document.createElement('div'),
|
|
annotation = {text: 'text \nwith\r\nline\n\rbreaks \r'};
|
|
|
|
annotators[0].viewer.fields[0].load(field, annotation);
|
|
expect($(field).html()).toBe('text <br>with<br>line<br>breaks <br>');
|
|
});
|
|
|
|
it('should set the contents of the field to placeholder text when empty', function() {
|
|
var field = document.createElement('div'),
|
|
annotation = {text: ''};
|
|
|
|
annotators[0].viewer.fields[0].load(field, annotation);
|
|
expect($(field).html()).toBe('<i>No Comment</i>');
|
|
});
|
|
|
|
it('should setup the default text field to publish an event on load', function() {
|
|
var field = document.createElement('div'),
|
|
annotation = {text: ''},
|
|
callback = jasmine.createSpy();
|
|
|
|
annotators[0].on('annotationViewerTextField', callback);
|
|
annotators[0].viewer.fields[0].load(field, annotation);
|
|
expect(callback).toHaveBeenCalledWith(field, annotation);
|
|
});
|
|
|
|
it('should subscribe to custom events', function() {
|
|
expect(mockViewer.on).toHaveBeenCalledWith('edit', annotators[0].onEditAnnotation);
|
|
expect(mockViewer.on).toHaveBeenCalledWith('delete', annotators[0].onDeleteAnnotation);
|
|
});
|
|
|
|
it('should bind to browser mouseover and mouseout events', function() {
|
|
expect(mockViewer.element.bind).toHaveBeenCalledWith({
|
|
mouseover: annotators[0].clearViewerHideTimer,
|
|
mouseout: annotators[0].startViewerHideTimer
|
|
});
|
|
});
|
|
|
|
it('should append the Viewer#element to the Annotator#wrapper', function() {
|
|
expect(mockViewer.element.appendTo).toHaveBeenCalledWith(annotators[0].wrapper);
|
|
});
|
|
});
|
|
|
|
describe('TagsPlugin', function() {
|
|
it('should add ARIA label information to the viewer', function() {
|
|
var tagDiv,
|
|
annotation = {
|
|
id: '01',
|
|
text: 'Test text',
|
|
tags: ['tag1', 'tag2', 'tag3'],
|
|
highlights: [highlights[0].get(0)]
|
|
};
|
|
|
|
annotators[0].viewer.load([annotation]);
|
|
tagDiv = annotators[0].viewer.element.find('.annotator-tags');
|
|
expect($(tagDiv).attr('role')).toEqual('region');
|
|
expect($(tagDiv).attr('aria-label')).toEqual('tags');
|
|
|
|
// Three children for the individual tags.
|
|
expect($(tagDiv).children().length).toEqual(3);
|
|
});
|
|
|
|
it('should add screen reader label to the editor', function() {
|
|
var srLabel, editor, inputId;
|
|
|
|
// We don't know exactly what the input ID will be (depends on number of annotatable components shown),
|
|
// but the sr label "for" attribute should match the ID of the element immediately following it.
|
|
annotators[0].showEditor({}, {});
|
|
editor = annotators[0].editor;
|
|
srLabel = editor.element.find('label.sr');
|
|
inputId = srLabel.next().attr('id');
|
|
expect(srLabel.attr('for')).toEqual(inputId);
|
|
});
|
|
});
|
|
});
|
|
});
|