blob: bd7994792523a0b22805fbf042d80f6151b7846a [file] [log] [blame]
<!DOCTYPE html>
<html>
<link rel="import" href="../resources/chai.html" />
<link rel="import" href="../resources/mocha.html" />
<script>
describe('MutationObserver.observe on a subtree', function() {
it('should handle basic aspects of subtree observation', function(done) {
var observer;
var subDiv;
var mutations;
function start() {
var div = document.createElement('div');
subDiv = div.appendChild(document.createElement('div'));
subDiv.textContent = 'hello, world';
observer = new MutationObserver(function(records) {
mutations = records;
});
observer.observe(div, {attributes: true, characterData: true, subtree: true});
subDiv.setAttribute('foo', 'bar');
subDiv.firstChild.textContent = 'goodbye!';
setTimeout(finish, 0);
}
function finish() {
// ...attribute and characterData changes in subtree
assert.equal(mutations.length, 2);
assert.equal(mutations[0].type, "attributes");
assert.equal(mutations[0].target, subDiv);
assert.equal(mutations[0].attributeName, "foo");
assert.equal(mutations[1].type, "characterData");
assert.equal(mutations[1].target, subDiv.firstChild);
observer.disconnect();
done();
}
start();
});
it('should handle two observers at different depths', function(done) {
var observer;
var observer2;
var mutations;
var mutations2;
var subDiv;
function start() {
var div = document.createElement('div');
subDiv = div.appendChild(document.createElement('div'));
observer = new MutationObserver(function(records) {
mutations = records;
});
observer2 = new MutationObserver(function(records) {
mutations2 = records;
});
observer.observe(div, {attributes: true, subtree: true});
observer2.observe(subDiv, {attributes: true});
subDiv.setAttribute('foo', 'bar');
setTimeout(finish, 0);
}
function finish() {
assert.equal(mutations.length, 1);
assert.equal(mutations[0].type, "attributes");
assert.equal(mutations[0].target, subDiv);
assert.equal(mutations[0].attributeName, "foo");
assert.equal(mutations2.length, 1);
assert.equal(mutations2[0].type, "attributes");
assert.equal(mutations2[0].target, subDiv);
assert.equal(mutations2[0].attributeName, "foo");
observer.disconnect();
observer2.disconnect();
done();
}
start();
});
it('should handle one observer at two different depths', function(done) {
var observer;
var mutations;
var calls = 0;
var subDiv;
function start() {
var div = document.createElement('div');
subDiv = div.appendChild(document.createElement('div'));
observer = new MutationObserver(function(records) {
mutations = records;
++calls;
});
observer.observe(div, {attributes: true, subtree: true});
observer.observe(subDiv, {attributes: true, subtree: true});
subDiv.setAttribute('foo', 'bar');
setTimeout(finish, 0);
}
function finish() {
assert.equal(calls, 1);
assert.equal(mutations.length, 1);
assert.equal(mutations[0].type, "attributes");
assert.equal(mutations[0].target, subDiv);
assert.equal(mutations[0].attributeName, "foo");
observer.disconnect();
done();
}
start();
});
// FIXME(sky): This test is huge, it should be broken up.
it('should handle transiently detached nodes are still observed via subtree', function(done) {
var observer;
var mutations;
var div;
var subDiv;
function start() {
div = document.createElement('div');
subDiv = div.appendChild(document.createElement('div'));
subDiv.textContent = 'hello, world';
observer = new MutationObserver(function(records) {
mutations = records;
});
observer.observe(div, {attributes: true, characterData: true, subtree: true});
subDiv.setAttribute('foo', 'bar');
div.removeChild(subDiv);
subDiv.setAttribute('test', 'test');
setTimeout(checkDeliveredAndChangeAgain, 0);
}
function checkDeliveredAndChangeAgain() {
// ...both changes should be received. Change detached subDiv again.
assert.equal(mutations.length, 2);
assert.equal(mutations[0].type, "attributes");
assert.equal(mutations[0].target, subDiv);
assert.equal(mutations[0].attributeName, "foo");
assert.equal(mutations[1].type, "attributes");
assert.equal(mutations[1].target, subDiv);
assert.equal(mutations[1].attributeName, "test");
mutations = null;
subDiv.setAttribute('foo', 'baz');
setTimeout(checkNotDeliveredAndReattach, 0);
}
function checkNotDeliveredAndReattach() {
// ...transient subtree observation was stopped after delivery, so subDiv change should not be received. Reattach and change again.
assert.equal(mutations, null);
mutations = null
div.appendChild(subDiv);
subDiv.setAttribute('foo', 'bat');
setTimeout(checkDeliveredAndReobserve, 0);
}
function checkDeliveredAndReobserve() {
//...reattached subtree should now be observable. Try detaching and re-observing.
assert.equal(mutations.length, 1);
assert.equal(mutations[0].type, "attributes");
assert.equal(mutations[0].target, subDiv);
assert.equal(mutations[0].attributeName, "foo");
mutations = null;
div.removeChild(subDiv);
subDiv.firstChild.textContent = 'badbye';
observer.observe(div, {attributes: true, characterData: true, subtree: true});
subDiv.setAttribute('foo', 'boo');
setTimeout(finish, 0);
}
function finish() {
// ...The change made before re-observing should be received, but not the one after.
assert.equal(mutations.length, 1);
assert.equal(mutations[0].type, "characterData");
assert.equal(mutations[0].target, subDiv.firstChild);
observer.disconnect();
done();
}
start();
});
it('should have correct behavior of transient observation with complex movement', function(done) {
var observer;
var subDiv;
var mutations;
function start() {
var div = document.createElement('div');
subDiv = div.appendChild(document.createElement('div'));
subDiv2 = subDiv.appendChild(document.createElement('div'));
subDiv2.textContent = 'hello, world';
subDiv3 = document.createElement('div');
observer = new MutationObserver(function(records) {
mutations = records;
});
observer.observe(div, {attributes: true, characterData: true, subtree: true});
div.removeChild(subDiv);
subDiv.removeChild(subDiv2);
text = subDiv2.removeChild(subDiv2.firstChild);
subDiv.setAttribute('a', 'a');
subDiv2.setAttribute('b', 'b');
text.textContent = 'c';
subDiv3.appendChild(subDiv2);
subDiv3.setAttribute('d', 'd');
subDiv2.setAttribute('e', 'e');
div.appendChild(subDiv3);
subDiv3.setAttribute('f', 'f');
subDiv2.setAttribute('g', 'g');
setTimeout(finish, 0);
}
function finish() {
// ...All changes should be received except for setting the "d" attribute on subDiv3 before it was reachable from div.
assert.equal(mutations.length, 6);
assert.equal(mutations[0].type, "attributes");
assert.equal(mutations[0].target, subDiv);
assert.equal(mutations[0].attributeName, "a");
assert.equal(mutations[1].type, "attributes");
assert.equal(mutations[1].target, subDiv2);
assert.equal(mutations[1].attributeName, "b");
assert.equal(mutations[2].type, "characterData");
assert.equal(mutations[2].target, text);
assert.equal(mutations[3].type, "attributes");
assert.equal(mutations[3].target, subDiv2);
assert.equal(mutations[3].attributeName, "e");
assert.equal(mutations[4].type, "attributes");
assert.equal(mutations[4].target, subDiv3);
assert.equal(mutations[4].attributeName, "f");
assert.equal(mutations[5].type, "attributes");
assert.equal(mutations[5].target, subDiv2);
assert.equal(mutations[5].attributeName, "g");
observer.disconnect();
done();
}
start();
});
});
</script>
</html>