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'; 'use strict';
var assign = require('core-js/modules/$.object-assign');
var util = require('./util'); var util = require('./util');
var excerpt = require('../excerpt'); 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 () { function excerptDirective(attrs, content) {
var ctrl; 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() { before(function () {
ctrl = new excerpt.Controller(); angular.module('app', [])
ctrl.overflowing = function () { return false; }; .directive('excerpt', excerpt.directive);
}); });
it('starts collapsed if the element is overflowing', function () { beforeEach(function () {
ctrl.overflowing = function () { return true; }; angular.mock.module('app');
angular.mock.module('h.templates');
assert.isTrue(ctrl.collapsed());
}); });
it('does not start collapsed if the element is not overflowing', function () { describe('enabled state', function () {
assert.isFalse(ctrl.collapsed()); 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.equal(element.find('.excerpt #foo').length, 1);
assert.isFalse(ctrl.uncollapsed()); });
});
it('is not initially uncollapsed if the element is not overflowing', function () { it('when enabled, renders its contents in a .excerpt element', function () {
assert.isFalse(ctrl.uncollapsed()); var element = excerptDirective({enabled: true}, '<span id="foo"></span>');
});
describe('.toggle()', function () { assert.equal(element.find('.excerpt #foo').length, 1);
beforeEach(function () {
ctrl.overflowing = function () { return true; };
}); });
it('toggles the collapsed state', function () { it('when disabled, renders its contents but not in a .excerpt element', function () {
var a = ctrl.collapsed(); var element = excerptDirective({enabled: false}, '<span id="foo"></span>');
ctrl.toggle();
var b = ctrl.collapsed();
ctrl.toggle();
var c = ctrl.collapsed();
assert.notEqual(a, b); assert.equal(element.find('.excerpt #foo').length, 0);
assert.notEqual(b, c); assert.equal(element.find('#foo').length, 1);
assert.equal(a, c);
}); });
}); });
});
describe('excerpt.excerpt', function () { function isHidden(el) {
function excerptDirective(attrs, content) { return !el.offsetParent || el.classList.contains('ng-hide');
return util.createDirective(document, 'excerpt', attrs, {}, content);
} }
before(function () { function findVisible(el, selector) {
angular.module('app', []) var elements = el.querySelectorAll(selector);
.directive('excerpt', excerpt.directive); for (var i=0; i < elements.length; i++) {
}); if (!isHidden(elements[i])) {
return elements[i];
}
}
return undefined;
}
beforeEach(function () { describe('inline controls', function () {
angular.mock.module('app'); function findInlineControl(el) {
angular.mock.module('h.templates'); 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 () { it('does not display inline controls if not collapsed', function () {
var element = excerptDirective({}, '<span id="foo"></span>'); 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 () { describe('.collapse', function () {
var element = excerptDirective({enabled: true}, '<span id="foo"></span>'); 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 () { describe('.onCollapsibleChanged', function () {
var element = excerptDirective({enabled: false}, '<span id="foo"></span>'); 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); it('reports false if excerpt is short', function () {
assert.equal(element.find('#foo').length, 1); 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) { ...@@ -51,15 +51,21 @@ function hyphenate(name) {
* scope when the element is linked * scope when the element is linked
* @param {string} [initialHtml] - Initial inner HTML content for the directive * @param {string} [initialHtml] - Initial inner HTML content for the directive
* element. * 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. * @return {DOMElement} The Angular jqLite-wrapped DOM element for the component.
* The returned object has a link(scope) method which will * The returned object has a link(scope) method which will
* re-link the component with new properties. * re-link the component with new properties.
*/ */
function createDirective(document, name, attrs, initialScope, initialHtml) { function createDirective(document, name, attrs, initialScope, initialHtml, opts) {
attrs = attrs || {}; attrs = attrs || {};
initialScope = initialScope || {}; initialScope = initialScope || {};
initialHtml = initialHtml || ''; initialHtml = initialHtml || '';
opts = opts || {};
opts.parentElement = opts.parentElement || document.body;
// create a template consisting of a single element, the directive // create a template consisting of a single element, the directive
// we want to create and compile it // we want to create and compile it
...@@ -82,6 +88,11 @@ function createDirective(document, name, attrs, initialScope, initialHtml) { ...@@ -82,6 +88,11 @@ function createDirective(document, name, attrs, initialScope, initialHtml) {
}); });
templateElement.innerHTML = 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 // setup initial scope
Object.keys(attrs).forEach(function (key) { Object.keys(attrs).forEach(function (key) {
if (attrs[key].callback) { if (attrs[key].callback) {
...@@ -105,6 +116,7 @@ function createDirective(document, name, attrs, initialScope, initialHtml) { ...@@ -105,6 +116,7 @@ function createDirective(document, name, attrs, initialScope, initialHtml) {
element.link = linkDirective; element.link = linkDirective;
element.scope = childScope; element.scope = childScope;
childScope.$digest(); childScope.$digest();
element.ctrl = element.controller(name);
return element; 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