Commit 06b092bc authored by Robert Knight's avatar Robert Knight

Update tests for <excerpt> control

 * Remove the controller tests which no longer correspond
   to the implementation

 * Set default values for <excerpt> attributes needed
   by test

 * Add additional tests for toggling of the <excerpt>
   using inline controls and using properties to control
   expansion/collapse externally.
parent 7aaad32f
'use strict';
var assign = require('core-js/modules/$.object-assign');
var util = require('./util');
var excerpt = require('../excerpt');
describe('excerpt directive', function () {
var SHORT_DIV = '<div id="foo" style="height:5px;"></div>';
var TALL_DIV = '<div id="foo" style="height:200px;">foo bar</div>';
describe('excerpt.Controller', function () {
var ctrl;
function excerptDirective(attrs, content) {
var defaultAttrs = {
// disable animation so that expansion/collapse happens immediately
// when the controls are toggled in tests
animate: false,
enabled: true,
collapsedHeight: 40,
inlineControls: false,
};
attrs = assign(defaultAttrs, attrs);
return util.createDirective(document, 'excerpt', attrs, {}, content);
}
beforeEach(function() {
ctrl = new excerpt.Controller();
ctrl.overflowing = function () { return false; };
before(function () {
angular.module('app', [])
.directive('excerpt', excerpt.directive);
});
it('starts collapsed if the element is overflowing', function () {
ctrl.overflowing = function () { return true; };
assert.isTrue(ctrl.collapsed());
beforeEach(function () {
angular.mock.module('app');
angular.mock.module('h.templates');
});
it('does not start collapsed if the element is not overflowing', function () {
assert.isFalse(ctrl.collapsed());
});
describe('enabled state', function () {
it('renders its contents in a .excerpt element by default', function () {
var element = excerptDirective({}, '<span id="foo"></span>');
it('is not initially uncollapsed if the element is overflowing', function () {
assert.isFalse(ctrl.uncollapsed());
});
assert.equal(element.find('.excerpt #foo').length, 1);
});
it('is not initially uncollapsed if the element is not overflowing', function () {
assert.isFalse(ctrl.uncollapsed());
});
it('when enabled, renders its contents in a .excerpt element', function () {
var element = excerptDirective({enabled: true}, '<span id="foo"></span>');
describe('.toggle()', function () {
beforeEach(function () {
ctrl.overflowing = function () { return true; };
assert.equal(element.find('.excerpt #foo').length, 1);
});
it('toggles the collapsed state', function () {
var a = ctrl.collapsed();
ctrl.toggle();
var b = ctrl.collapsed();
ctrl.toggle();
var c = ctrl.collapsed();
it('when disabled, renders its contents but not in a .excerpt element', function () {
var element = excerptDirective({enabled: false}, '<span id="foo"></span>');
assert.notEqual(a, b);
assert.notEqual(b, c);
assert.equal(a, c);
assert.equal(element.find('.excerpt #foo').length, 0);
assert.equal(element.find('#foo').length, 1);
});
});
});
describe('excerpt.excerpt', function () {
function excerptDirective(attrs, content) {
return util.createDirective(document, 'excerpt', attrs, {}, content);
function isHidden(el) {
return !el.offsetParent || el.classList.contains('ng-hide');
}
before(function () {
angular.module('app', [])
.directive('excerpt', excerpt.directive);
});
function findVisible(el, selector) {
var elements = el.querySelectorAll(selector);
for (var i=0; i < elements.length; i++) {
if (!isHidden(elements[i])) {
return elements[i];
}
}
return undefined;
}
beforeEach(function () {
angular.mock.module('app');
angular.mock.module('h.templates');
});
describe('inline controls', function () {
function findInlineControl(el) {
return findVisible(el, '.excerpt__toggle-link');
}
it('displays inline controls if collapsed', function () {
var element = excerptDirective({inlineControls: true},
TALL_DIV);
element.scope.$digest();
var expandLink = findInlineControl(element[0]);
assert.ok(expandLink);
assert.equal(expandLink.querySelector('a').textContent, 'More');
});
it('renders its contents in a .excerpt element by default', function () {
var element = excerptDirective({}, '<span id="foo"></span>');
it('does not display inline controls if not collapsed', function () {
var element = excerptDirective({inlineControls: true},
SHORT_DIV);
var expandLink = findInlineControl(element[0]);
assert.notOk(expandLink);
});
assert.equal(element.find('.excerpt #foo').length, 1);
it('toggles the expanded state when clicked', function () {
var element = excerptDirective({inlineControls: true},
TALL_DIV);
element.scope.$digest();
var expandLink = findInlineControl(element[0]);
angular.element(expandLink.querySelector('a')).click();
element.scope.$digest();
var collapseLink = findInlineControl(element[0]);
assert.equal(collapseLink.querySelector('a').textContent, 'Less');
});
});
it('when enabled, renders its contents in a .excerpt element', function () {
var element = excerptDirective({enabled: true}, '<span id="foo"></span>');
describe('.collapse', function () {
function height(el) {
return el.querySelector('.excerpt').offsetHeight;
}
it('collapses the body if collapse is true', function () {
var element = excerptDirective({collapse: true}, TALL_DIV);
assert.isBelow(height(element[0]), 100);
});
assert.equal(element.find('.excerpt #foo').length, 1);
it('does not collapse the body if collapse is false', function () {
var element = excerptDirective({collapse: false}, TALL_DIV);
assert.isAbove(height(element[0]), 100);
});
});
it('when disabled, renders its contents but not in a .excerpt element', function () {
var element = excerptDirective({enabled: false}, '<span id="foo"></span>');
describe('.onCollapsibleChanged', function () {
it('reports true if excerpt is tall', function () {
var callback = sinon.stub();
var element = excerptDirective({
onCollapsibleChanged: {
args: ['collapsible'],
callback: callback,
}
}, TALL_DIV);
assert.calledWith(callback, true);
});
assert.equal(element.find('.excerpt #foo').length, 0);
assert.equal(element.find('#foo').length, 1);
it('reports false if excerpt is short', function () {
var callback = sinon.stub();
var element = excerptDirective({
onCollapsibleChanged: {
args: ['collapsible'],
callback: callback,
}
}, SHORT_DIV);
assert.calledWith(callback, false);
});
});
});
......@@ -51,15 +51,21 @@ function hyphenate(name) {
* scope when the element is linked
* @param {string} [initialHtml] - Initial inner HTML content for the directive
* element.
* @param {Object} [opts] - Object specifying options for creating the
* directive:
* 'parentElement' - The parent element for the new
* directive. Defaults to document.body
*
* @return {DOMElement} The Angular jqLite-wrapped DOM element for the component.
* The returned object has a link(scope) method which will
* re-link the component with new properties.
*/
function createDirective(document, name, attrs, initialScope, initialHtml) {
function createDirective(document, name, attrs, initialScope, initialHtml, opts) {
attrs = attrs || {};
initialScope = initialScope || {};
initialHtml = initialHtml || '';
opts = opts || {};
opts.parentElement = opts.parentElement || document.body;
// create a template consisting of a single element, the directive
// we want to create and compile it
......@@ -82,6 +88,11 @@ function createDirective(document, name, attrs, initialScope, initialHtml) {
});
templateElement.innerHTML = initialHtml;
// add the element to the document's body so that
// it responds to events, becomes visible, reports correct
// values for its dimensions etc.
opts.parentElement.appendChild(templateElement);
// setup initial scope
Object.keys(attrs).forEach(function (key) {
if (attrs[key].callback) {
......@@ -105,6 +116,7 @@ function createDirective(document, name, attrs, initialScope, initialHtml) {
element.link = linkDirective;
element.scope = childScope;
childScope.$digest();
element.ctrl = element.controller(name);
return element;
}
......
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