blob: 96cbf9e222f07230e228b9fd22ef82a3565f2928 [file] [log] [blame]
/* global describe:false, it:false, beforeEach:false, expect:false, elementResizeDetectorMaker:false, _:false, $:false, jasmine:false */
"use strict";
function ensureMapEqual(before, after, ignore) {
var beforeKeys = _.keys(before);
var afterKeys = _.keys(after);
var unionKeys = _.union(beforeKeys, afterKeys);
var diffValueKeys = _.filter(unionKeys, function (key) {
var beforeValue = before[key];
var afterValue = after[key];
return !ignore(key, beforeValue, afterValue) && beforeValue !== afterValue;
});
if (diffValueKeys.length) {
var beforeDiffObject = {};
var afterDiffObject = {};
_.forEach(diffValueKeys, function (key) {
beforeDiffObject[key] = before[key];
afterDiffObject[key] = after[key];
});
expect(afterDiffObject).toEqual(beforeDiffObject);
}
}
function getStyle(element) {
function clone(styleObject) {
var clonedTarget = {};
_.forEach(styleObject.cssText.split(";").slice(0, -1), function (declaration) {
var colonPos = declaration.indexOf(":");
var attr = declaration.slice(0, colonPos).trim();
if (attr.indexOf("-") === -1) { // Remove attributes like "background-image", leaving "backgroundImage"
clonedTarget[attr] = declaration.slice(colonPos + 2);
}
});
return clonedTarget;
}
var style = getComputedStyle(element);
return clone(style);
}
function getAttributes(element) {
var attrs = {};
_.forEach(element.attributes, function (attr) {
attrs[attr.nodeName] = attr.value;
});
return attrs;
}
var ensureAttributes = ensureMapEqual;
var reporter = {
log: function () {
throw new Error("Reporter.log should not be called");
},
warn: function () {
throw new Error("Reporter.warn should not be called");
},
error: function () {
throw new Error("Reporter.error should not be called");
}
};
$("body").prepend("<div id=fixtures></div>");
function listenToTest(strategy) {
describe("[" + strategy + "] listenTo", function () {
it("should be able to attach a listener to an element", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
reporter: reporter,
strategy: strategy
});
var listener = jasmine.createSpy("listener");
erd.listenTo($("#test")[0], listener);
setTimeout(function () {
$("#test").width(300);
}, 200);
setTimeout(function () {
expect(listener).toHaveBeenCalledWith($("#test")[0]);
done();
}, 400);
});
it("should throw on invalid parameters", function () {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
reporter: reporter,
strategy: strategy
});
expect(erd.listenTo).toThrow();
expect(_.partial(erd.listenTo, $("#test")[0])).toThrow();
});
describe("option.onReady", function () {
it("should be called when installing a listener to an element", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
reporter: reporter,
strategy: strategy
});
var listener = jasmine.createSpy("listener");
erd.listenTo({
onReady: function () {
$("#test").width(200);
setTimeout(function () {
expect(listener).toHaveBeenCalledWith($("#test")[0]);
done();
}, 200);
}
}, $("#test")[0], listener);
});
it("should be called when all elements are ready", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
reporter: reporter,
strategy: strategy
});
var listener = jasmine.createSpy("listener");
erd.listenTo({
onReady: function () {
$("#test").width(200);
$("#test2").width(300);
setTimeout(function () {
expect(listener).toHaveBeenCalledWith($("#test")[0]);
expect(listener).toHaveBeenCalledWith($("#test2")[0]);
done();
}, 200);
}
}, $("#test, #test2"), listener);
});
it("should be able to handle listeners for the same element but different calls", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
reporter: reporter,
strategy: strategy
});
var onReady1 = jasmine.createSpy("listener");
var onReady2 = jasmine.createSpy("listener");
erd.listenTo({
onReady: onReady1
}, $("#test"), function noop() {
});
erd.listenTo({
onReady: onReady2
}, $("#test"), function noop() {
});
setTimeout(function () {
expect(onReady1.calls.count()).toBe(1);
expect(onReady2.calls.count()).toBe(1);
done();
}, 300);
});
it("should be able to handle when elements occur multiple times in the same call (and other calls)", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
reporter: reporter,
strategy: strategy
});
var onReady1 = jasmine.createSpy("listener");
var onReady2 = jasmine.createSpy("listener");
erd.listenTo({
onReady: onReady1
}, [$("#test")[0], $("#test")[0]], function noop() {
});
erd.listenTo({
onReady: onReady2
}, $("#test"), function noop() {
});
setTimeout(function () {
expect(onReady1.calls.count()).toBe(1);
expect(onReady2.calls.count()).toBe(1);
done();
}, 300);
});
});
it("should be able to attach multiple listeners to an element", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
reporter: reporter,
strategy: strategy
});
var listener1 = jasmine.createSpy("listener1");
var listener2 = jasmine.createSpy("listener2");
erd.listenTo($("#test")[0], listener1);
erd.listenTo($("#test")[0], listener2);
setTimeout(function () {
$("#test").width(300);
}, 200);
setTimeout(function () {
expect(listener1).toHaveBeenCalledWith($("#test")[0]);
expect(listener2).toHaveBeenCalledWith($("#test")[0]);
done();
}, 400);
});
it("should be able to attach a listener to an element multiple times within the same call", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
reporter: reporter,
strategy: strategy
});
var listener1 = jasmine.createSpy("listener1");
erd.listenTo([$("#test")[0], $("#test")[0]], listener1);
setTimeout(function () {
$("#test").width(300);
}, 200);
setTimeout(function () {
expect(listener1).toHaveBeenCalledWith($("#test")[0]);
expect(listener1.calls.count()).toBe(2);
done();
}, 400);
});
it("should be able to attach listeners to multiple elements", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
reporter: reporter,
strategy: strategy
});
var listener1 = jasmine.createSpy("listener1");
erd.listenTo($("#test, #test2"), listener1);
setTimeout(function () {
$("#test").width(200);
}, 200);
setTimeout(function () {
expect(listener1).toHaveBeenCalledWith($("#test")[0]);
}, 400);
setTimeout(function () {
$("#test2").width(500);
}, 600);
setTimeout(function () {
expect(listener1).toHaveBeenCalledWith($("#test2")[0]);
done();
}, 800);
});
//Only run this test if the browser actually is able to get the computed style of an element.
//Only IE8 is lacking the getComputedStyle method.
if (window.getComputedStyle) {
it("should keep the style of the element intact", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
reporter: reporter,
strategy: strategy
});
function ignoreStyleChange(key, before, after) {
return (key === "position" && before === "static" && after === "relative") ||
(/^(top|right|bottom|left)$/.test(key) && before === "auto" && after === "0px");
}
var beforeComputedStyle = getStyle($("#test")[0]);
erd.listenTo($("#test")[0], _.noop);
var afterComputedStyle = getStyle($("#test")[0]);
ensureMapEqual(beforeComputedStyle, afterComputedStyle, ignoreStyleChange);
//Test styles async since making an element listenable is async.
setTimeout(function () {
var afterComputedStyleAsync = getStyle($("#test")[0]);
ensureMapEqual(beforeComputedStyle, afterComputedStyleAsync, ignoreStyleChange);
expect(true).toEqual(true); // Needed so that jasmine does not warn about no expects in the test (the actual expects are in the ensureMapEqual).
done();
}, 200);
});
}
describe("options.callOnAdd", function () {
it("should be true default and call all functions when listenTo succeeds", function (done) {
var erd = elementResizeDetectorMaker({
reporter: reporter,
strategy: strategy
});
var listener = jasmine.createSpy("listener");
var listener2 = jasmine.createSpy("listener2");
erd.listenTo($("#test")[0], listener);
erd.listenTo($("#test")[0], listener2);
setTimeout(function () {
expect(listener).toHaveBeenCalledWith($("#test")[0]);
expect(listener2).toHaveBeenCalledWith($("#test")[0]);
listener.calls.reset();
listener2.calls.reset();
$("#test").width(300);
}, 200);
setTimeout(function () {
expect(listener).toHaveBeenCalledWith($("#test")[0]);
expect(listener2).toHaveBeenCalledWith($("#test")[0]);
done();
}, 400);
});
it("should call listener multiple times when listening to multiple elements", function (done) {
var erd = elementResizeDetectorMaker({
reporter: reporter,
strategy: strategy
});
var listener1 = jasmine.createSpy("listener1");
erd.listenTo($("#test, #test2"), listener1);
setTimeout(function () {
expect(listener1).toHaveBeenCalledWith($("#test")[0]);
expect(listener1).toHaveBeenCalledWith($("#test2")[0]);
done();
}, 200);
});
});
it("should call listener if the element is changed synchronously after listenTo", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
reporter: reporter,
strategy: strategy
});
var listener1 = jasmine.createSpy("listener1");
erd.listenTo($("#test"), listener1);
$("#test").width(200);
setTimeout(function () {
expect(listener1).toHaveBeenCalledWith($("#test")[0]);
done();
}, 200);
});
it("should not emit resize when listenTo is called", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
reporter: reporter,
strategy: strategy
});
var listener1 = jasmine.createSpy("listener1");
erd.listenTo($("#test"), listener1);
setTimeout(function () {
expect(listener1).not.toHaveBeenCalledWith($("#test")[0]);
done();
}, 200);
});
it("should not emit resize event even though the element is back to its start size", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
reporter: reporter,
strategy: strategy
});
var listener = jasmine.createSpy("listener1");
$("#test").width(200);
erd.listenTo($("#test"), listener);
setTimeout(function () {
expect(listener).not.toHaveBeenCalledWith($("#test")[0]);
listener.calls.reset();
$("#test").width(100);
}, 200);
setTimeout(function () {
expect(listener).toHaveBeenCalledWith($("#test")[0]);
listener.calls.reset();
$("#test").width(200);
}, 400);
setTimeout(function () {
expect(listener).toHaveBeenCalledWith($("#test")[0]);
done();
}, 600);
});
it("should use the option.idHandler if present", function (done) {
var ID_ATTR = "some-fancy-id-attr";
var idHandler = {
get: function (element, readonly) {
if (element[ID_ATTR] === undefined) {
if (readonly) {
return null;
}
this.set(element);
}
return $(element).attr(ID_ATTR);
},
set: function (element) {
var id;
if ($(element).attr("id") === "test") {
id = "test+1";
} else if ($(element).attr("id") === "test2") {
id = "test2+2";
}
$(element).attr(ID_ATTR, id);
return id;
}
};
var erd = elementResizeDetectorMaker({
idHandler: idHandler,
callOnAdd: false,
reporter: reporter,
strategy: strategy
});
var listener1 = jasmine.createSpy("listener1");
var listener2 = jasmine.createSpy("listener1");
var attrsBeforeTest = getAttributes($("#test")[0]);
var attrsBeforeTest2 = getAttributes($("#test2")[0]);
erd.listenTo($("#test"), listener1);
erd.listenTo($("#test, #test2"), listener2);
var attrsAfterTest = getAttributes($("#test")[0]);
var attrsAfterTest2 = getAttributes($("#test2")[0]);
var ignoreValidIdAttrAndStyle = function (key) {
return key === ID_ATTR || key === "style";
};
ensureAttributes(attrsBeforeTest, attrsAfterTest, ignoreValidIdAttrAndStyle);
ensureAttributes(attrsBeforeTest2, attrsAfterTest2, ignoreValidIdAttrAndStyle);
expect($("#test").attr(ID_ATTR)).toEqual("test+1");
expect($("#test2").attr(ID_ATTR)).toEqual("test2+2");
setTimeout(function () {
$("#test").width(300);
$("#test2").width(500);
}, 200);
setTimeout(function () {
expect(listener1).toHaveBeenCalledWith($("#test")[0]);
expect(listener2).toHaveBeenCalledWith($("#test")[0]);
expect(listener2).toHaveBeenCalledWith($("#test2")[0]);
done();
}, 600);
});
it("should be able to install into elements that are detached from the DOM", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
reporter: reporter,
strategy: strategy
});
var listener1 = jasmine.createSpy("listener1");
var div = document.createElement("div");
div.style.width = "100%";
div.style.height = "100%";
erd.listenTo(div, listener1);
setTimeout(function () {
$("#test")[0].appendChild(div);
}, 200);
setTimeout(function () {
$("#test").width(200);
}, 400);
setTimeout(function () {
expect(listener1).toHaveBeenCalledWith(div);
done();
}, 600);
});
it("should handle iframes, by using initDocument", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
strategy: strategy,
reporter: reporter
});
var listener1 = jasmine.createSpy("listener1");
var iframe = document.createElement("iframe");
$("#test")[0].appendChild(iframe);
erd.initDocument(iframe.contentDocument);
var div = iframe.contentDocument.createElement("div");
div.style.width = "100%";
div.style.height = "100%";
div.id = "target";
erd.listenTo(div, listener1);
setTimeout(function () {
// FireFox triggers the onload state of the iframe and wipes its content.
iframe.contentDocument.body.appendChild(div);
erd.initDocument(iframe.contentDocument);
}, 10);
setTimeout(function () {
div.style.width = "100px";
}, 200);
setTimeout(function () {
expect(listener1).toHaveBeenCalledWith(div);
done();
}, 400);
});
it("should detect resizes caused by padding and font-size changes", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
reporter: reporter,
strategy: strategy
});
var listener = jasmine.createSpy("listener");
$("#test").html("test");
$("#test").css("padding", "0px");
$("#test").css("font-size", "16px");
erd.listenTo($("#test"), listener);
$("#test").css("padding", "10px");
setTimeout(function () {
expect(listener).toHaveBeenCalledWith($("#test")[0]);
listener.calls.reset();
$("#test").css("font-size", "20px");
}, 200);
setTimeout(function () {
expect(listener).toHaveBeenCalledWith($("#test")[0]);
done();
}, 400);
});
describe("should handle unrendered elements correctly", function () {
it("when installing", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
reporter: reporter,
strategy: strategy
});
$("#test").html("<div id=\"inner\"></div>");
$("#test").css("display", "none");
var listener = jasmine.createSpy("listener");
erd.listenTo($("#inner"), listener);
setTimeout(function () {
expect(listener).not.toHaveBeenCalled();
$("#test").css("display", "");
}, 200);
setTimeout(function () {
expect(listener).toHaveBeenCalledWith($("#inner")[0]);
listener.calls.reset();
$("#inner").width("300px");
}, 400);
setTimeout(function () {
expect(listener).toHaveBeenCalledWith($("#inner")[0]);
listener.calls.reset();
done();
}, 600);
});
it("when element gets unrendered after installation", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
reporter: reporter,
strategy: strategy
});
// The div is rendered to begin with.
$("#test").html("<div id=\"inner\"></div>");
var listener = jasmine.createSpy("listener");
erd.listenTo($("#inner"), listener);
// The it gets unrendered, and it changes width.
setTimeout(function () {
expect(listener).not.toHaveBeenCalled();
$("#test").css("display", "none");
$("#inner").width("300px");
}, 100);
// Render the element again.
setTimeout(function () {
expect(listener).not.toHaveBeenCalled();
$("#test").css("display", "");
}, 200);
// ERD should detect that the element has changed size as soon as it gets rendered again.
setTimeout(function () {
expect(listener).toHaveBeenCalledWith($("#inner")[0]);
done();
}, 300);
});
});
describe("inline elements", function () {
it("should be listenable", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
reporter: reporter,
strategy: strategy
});
$("#test").html("<span id=\"inner\">test</span>");
var listener = jasmine.createSpy("listener");
erd.listenTo($("#inner"), listener);
setTimeout(function () {
expect(listener).not.toHaveBeenCalled();
$("#inner").append("testing testing");
}, 100);
setTimeout(function () {
expect(listener).toHaveBeenCalledWith($("#inner")[0]);
done();
}, 200);
});
it("should not get altered dimensions", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
reporter: reporter,
strategy: strategy
});
$("#test").html("<span id=\"inner\"></span>");
var widthBefore = $("#inner").width();
var heightBefore = $("#inner").height();
var listener = jasmine.createSpy("listener");
erd.listenTo($("#inner"), listener);
setTimeout(function () {
expect($("#inner").width()).toEqual(widthBefore);
expect($("#inner").height()).toEqual(heightBefore);
done();
}, 100);
});
});
it("should handle dir=rtl correctly", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
reporter: reporter,
strategy: strategy
});
var listener = jasmine.createSpy("listener");
$("#test")[0].dir = "rtl";
erd.listenTo($("#test")[0], listener);
setTimeout(function () {
$("#test").width(300);
}, 200);
setTimeout(function () {
expect(listener).toHaveBeenCalledWith($("#test")[0]);
done();
}, 400);
});
it("should handle fast consecutive resizes", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
strategy: strategy,
reporter: reporter
});
var listener = jasmine.createSpy("listener");
$("#test").width(100);
erd.listenTo($("#test")[0], listener);
setTimeout(function () {
$("#test").width(300);
}, 50);
setTimeout(function () {
expect(listener.calls.count()).toEqual(1);
$("#test").width(500);
setTimeout(function () {
$("#test").width(300);
}, 0);
}, 100);
// Some browsers skip the 300 -> 500 -> 300 resize, and some actually processes it.
// So the resize events may be 1 or 3 at this point.
setTimeout(function () {
var count = listener.calls.count();
expect(count === 1 || count === 3).toEqual(true);
}, 150);
setTimeout(function () {
var count = listener.calls.count();
expect(count === 1 || count === 3).toEqual(true);
$("#test").width(800);
}, 200);
setTimeout(function () {
var count = listener.calls.count();
expect(count === 2 || count === 4).toEqual(true);
done();
}, 250);
});
});
}
function removalTest(strategy) {
describe("[" + strategy + "] resizeDetector.removeListener", function () {
it("should remove listener from element", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
strategy: strategy
});
var $testElem = $("#test");
var listenerCall = jasmine.createSpy("listener");
var listenerNotCall = jasmine.createSpy("listener");
erd.listenTo($testElem[0], listenerCall);
erd.listenTo($testElem[0], listenerNotCall);
setTimeout(function () {
erd.removeListener($testElem[0], listenerNotCall);
$testElem.width(300);
}, 200);
setTimeout(function () {
expect(listenerCall).toHaveBeenCalled();
expect(listenerNotCall).not.toHaveBeenCalled();
done();
}, 400);
});
});
describe("[" + strategy + "] resizeDetector.removeAllListeners", function () {
it("should remove all listeners from element", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
strategy: strategy
});
var $testElem = $("#test");
var listener1 = jasmine.createSpy("listener");
var listener2 = jasmine.createSpy("listener");
erd.listenTo($testElem[0], listener1);
erd.listenTo($testElem[0], listener2);
setTimeout(function () {
erd.removeAllListeners($testElem[0]);
$testElem.width(300);
}, 200);
setTimeout(function () {
expect(listener1).not.toHaveBeenCalled();
expect(listener2).not.toHaveBeenCalled();
done();
}, 400);
});
it("should work for elements that don't have the detector installed", function () {
var erd = elementResizeDetectorMaker({
strategy: strategy
});
var $testElem = $("#test");
expect(erd.removeAllListeners.bind(erd, $testElem[0])).not.toThrow();
});
});
describe("[scroll] Specific scenarios", function () {
it("should be able to call uninstall in the middle of a resize", function (done) {
var erd = elementResizeDetectorMaker({
strategy: "scroll"
});
var $testElem = $("#test");
var testElem = $testElem[0];
var listener = jasmine.createSpy("listener");
erd.listenTo(testElem, listener);
setTimeout(function () {
// We want the uninstall to happen exactly when a scroll event occured before the delayed batched is going to be processed.
// So we intercept the erd shrink/expand functions in the state so that we may call uninstall after the handling of the event.
var uninstalled = false;
function wrapOnScrollEvent(oldFn) {
return function () {
oldFn();
if (!uninstalled) {
expect(erd.uninstall.bind(erd, testElem)).not.toThrow();
uninstalled = true;
done();
}
};
}
var state = testElem._erd;
state.onExpand = wrapOnScrollEvent(state.onExpand);
state.onShrink = wrapOnScrollEvent(state.onShrink);
$("#test").width(300);
}, 50);
});
it("should be able to call uninstall and then install in the middle of a resize (issue #61)", function (done) {
var erd = elementResizeDetectorMaker({
strategy: "scroll",
reporter: reporter
});
var $testElem = $("#test");
var testElem = $testElem[0];
var listener = jasmine.createSpy("listener");
erd.listenTo(testElem, listener);
setTimeout(function () {
// We want the uninstall to happen exactly when a scroll event occured before the delayed batched is going to be processed.
// So we intercept the erd shrink/expand functions in the state so that we may call uninstall after the handling of the event.
var uninstalled = false;
function wrapOnScrollEvent(oldFn) {
return function () {
oldFn();
if (!uninstalled) {
expect(erd.uninstall.bind(erd, testElem)).not.toThrow();
uninstalled = true;
var listener2 = jasmine.createSpy("listener");
expect(erd.listenTo.bind(erd, testElem, listener2)).not.toThrow();
setTimeout(function () {
done();
}, 0);
}
};
}
var state = testElem._erd;
state.onExpand = wrapOnScrollEvent(state.onExpand);
state.onShrink = wrapOnScrollEvent(state.onShrink);
$("#test").width(300);
}, 50);
});
// Only run this shadow DOM test for browsers that support the feature
if (!!HTMLElement.prototype.attachShadow) {
it("should work for elements within an open shadow root (issue #127)", function(done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
reporter: reporter,
strategy: "scroll"
});
var listener = jasmine.createSpy("listener");
// Setup shadow root with a child div
var shadow = $("#shadowtest")[0].attachShadow({mode: "open"});
var shadowChild = document.createElement("div");
shadow.appendChild(shadowChild);
erd.listenTo(shadowChild, listener);
setTimeout(function () {
$(shadowChild).width(300);
}, 200);
setTimeout(function () {
expect(listener).toHaveBeenCalledWith(shadowChild);
done();
}, 400);
});
}
});
describe("[" + strategy + "] resizeDetector.uninstall", function () {
it("should completely remove detector from element", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
strategy: strategy
});
var $testElem = $("#test");
var listener = jasmine.createSpy("listener");
erd.listenTo($testElem[0], listener);
setTimeout(function () {
erd.uninstall($testElem[0]);
// detector element should be removed
expect($testElem[0].childNodes.length).toBe(0);
$testElem.width(300);
}, 200);
setTimeout(function () {
expect(listener).not.toHaveBeenCalled();
done();
}, 400);
});
it("should completely remove detector from multiple elements", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
strategy: strategy
});
var listener = jasmine.createSpy("listener");
erd.listenTo($("#test, #test2"), listener);
setTimeout(function () {
erd.uninstall($("#test, #test2"));
// detector element should be removed
expect($("#test")[0].childNodes.length).toBe(0);
expect($("#test2")[0].childNodes.length).toBe(0);
$("#test, #test2").width(300);
}, 200);
setTimeout(function () {
expect(listener).not.toHaveBeenCalled();
done();
}, 400);
});
it("should be able to call uninstall directly after listenTo", function () {
var erd = elementResizeDetectorMaker({
strategy: strategy
});
var $testElem = $("#test");
var listener = jasmine.createSpy("listener");
erd.listenTo($testElem[0], listener);
expect(erd.uninstall.bind(erd, $testElem[0])).not.toThrow();
});
it("should be able to call uninstall directly async after listenTo", function (done) {
var erd = elementResizeDetectorMaker({
strategy: strategy
});
var $testElem = $("#test");
var listener = jasmine.createSpy("listener");
erd.listenTo($testElem[0], listener);
setTimeout(function () {
expect(erd.uninstall.bind(erd, $testElem[0])).not.toThrow();
done();
}, 0);
});
it("should be able to call uninstall in callOnAdd callback", function (done) {
var error = false;
// Ugly hack to catch async errors.
window.onerror = function () {
error = true;
};
var erd = elementResizeDetectorMaker({
strategy: strategy,
callOnAdd: true
});
erd.listenTo($("#test"), function () {
expect(erd.uninstall.bind(null, ($("#test")))).not.toThrow();
});
setTimeout(function () {
expect(error).toBe(false);
done();
window.error = null;
}, 50);
});
it("should be able to call uninstall in callOnAdd callback with multiple elements", function (done) {
var error = false;
// Ugly hack to catch async errors.
window.onerror = function () {
error = true;
};
var erd = elementResizeDetectorMaker({
strategy: strategy,
callOnAdd: true
});
var listener = jasmine.createSpy("listener");
erd.listenTo($("#test, #test2"), function () {
expect(erd.uninstall.bind(null, ($("#test, #test2")))).not.toThrow();
listener();
});
setTimeout(function () {
expect(listener.calls.count()).toBe(1);
expect(error).toBe(false);
done();
window.error = null;
}, 50);
});
it("should be able to call uninstall on non-erd elements", function () {
var erd = elementResizeDetectorMaker({
strategy: strategy
});
var $testElem = $("#test");
expect(erd.uninstall.bind(erd, $testElem[0])).not.toThrow();
var listener = jasmine.createSpy("listener");
erd.listenTo($testElem[0], listener);
expect(erd.uninstall.bind(erd, $testElem[0])).not.toThrow();
expect(erd.uninstall.bind(erd, $testElem[0])).not.toThrow();
});
});
}
function importantRuleTest(strategy) {
describe("[" + strategy + "] resizeDetector.important", function () {
it("should add all rules with important", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: true,
strategy: strategy,
important: true
});
var testElem = $("#test");
var listenerCall = jasmine.createSpy("listener");
erd.listenTo(testElem[0], listenerCall);
setTimeout(function () {
if (strategy === "scroll") {
expect(testElem[0].style.cssText).toMatch(/!important;$/);
}
testElem.find("*").toArray().forEach(function (element) {
var rules = element.style.cssText.split(";").filter(function (rule) {
return !!rule;
});
rules.forEach(function (rule) {
expect(rule).toMatch(/!important$/);
});
});
done();
}, 50);
});
it("Overrides important CSS", function (done) {
var erd = elementResizeDetectorMaker({
callOnAdd: false,
strategy: strategy,
important: true
});
var listener = jasmine.createSpy("listener");
var testElem = $("#test");
var style = document.createElement("style");
style.appendChild(document.createTextNode("#test { position: static !important; }"));
document.head.appendChild(style);
erd.listenTo(testElem[0], listener);
setTimeout(function () {
$("#test").width(300);
}, 100);
setTimeout(function () {
expect(listener).toHaveBeenCalledWith($("#test")[0]);
done();
}, 200);
});
});
}
describe("element-resize-detector", function () {
beforeEach(function () {
//This messed with tests in IE8.
//TODO: Investigate why, because it would be nice to have instead of the current solution.
//loadFixtures("element-resize-detector_fixture.html");
$("#fixtures").html("<div id=test></div><div id=test2></div><div id=shadowtest></div>");
});
describe("elementResizeDetectorMaker", function () {
it("should be globally defined", function () {
expect(elementResizeDetectorMaker).toBeDefined();
});
it("should create an element-resize-detector instance", function () {
var erd = elementResizeDetectorMaker();
expect(erd).toBeDefined();
expect(erd.listenTo).toBeDefined();
});
});
// listenToTest("object");
// removalTest("object");
// importantRuleTest("object");
listenToTest("scroll");
removalTest("scroll");
importantRuleTest("scroll");
});