424 lines
12 KiB
HTML
424 lines
12 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<script src="../../../resources/js-test-pre.js"></script>
|
|
<title></title>
|
|
</head>
|
|
<body>
|
|
<p id=description></p>
|
|
<div id="console"></div>
|
|
<script>
|
|
|
|
window.jsTestIsAsync = true;
|
|
var mutations, mutations2;
|
|
var calls;
|
|
var div, removedDiv1, removedDiv2, addedDiv1, addedDiv2, addedDiv3;
|
|
|
|
function testBasic() {
|
|
var div;
|
|
var observer;
|
|
|
|
function start() {
|
|
debug('Testing basic aspects of childList observation.');
|
|
|
|
mutations = null;
|
|
div = document.createElement('div');
|
|
observer = new MutationObserver(function(m) {
|
|
mutations = m;
|
|
});
|
|
|
|
observer.observe(div, { childList: true });
|
|
removedDiv1 = div.appendChild(document.createElement('div'));
|
|
setTimeout(checkDisconnectAndMutate, 0);
|
|
}
|
|
|
|
function checkDisconnectAndMutate() {
|
|
debug('...can childList changes be observed at all');
|
|
|
|
shouldBe('mutations.length', '1');
|
|
shouldBe('mutations[0].type', '"childList"');
|
|
shouldBe('mutations[0].addedNodes.length', '1');
|
|
shouldBe('mutations[0].addedNodes[0]', 'removedDiv1');
|
|
|
|
mutations = null;
|
|
observer.disconnect();
|
|
removedDiv1 = div.appendChild(document.createElement('div'));
|
|
setTimeout(checkNotDeliveredAndMutateMultiple, 0);
|
|
}
|
|
|
|
function checkNotDeliveredAndMutateMultiple() {
|
|
debug('...observer.disconnect() should prevent further delivery of mutations.');
|
|
|
|
shouldBe('mutations', 'null');
|
|
observer.observe(div, { childList: true });
|
|
removedDiv1 = div.removeChild(div.firstChild);
|
|
removedDiv2 = div.removeChild(div.firstChild);
|
|
setTimeout(finish);
|
|
}
|
|
|
|
function finish() {
|
|
debug('...re-observing after disconnect works with the same observer.');
|
|
|
|
shouldBe('mutations.length', '2');
|
|
shouldBe('mutations[0].type', '"childList"');
|
|
shouldBe('mutations[0].removedNodes.length', '1');
|
|
shouldBe('mutations[0].removedNodes[0]', 'removedDiv1');
|
|
shouldBe('mutations[1].type', '"childList"');
|
|
shouldBe('mutations[1].removedNodes.length', '1');
|
|
shouldBe('mutations[1].removedNodes[0]', 'removedDiv2');
|
|
observer.disconnect();
|
|
debug('');
|
|
runNextTest();
|
|
}
|
|
|
|
start();
|
|
}
|
|
|
|
function testWrongType() {
|
|
var div;
|
|
var observer;
|
|
|
|
function start() {
|
|
debug('Testing that observing without specifying "childList" does not result in hearing about childList changes.');
|
|
|
|
mutations = null;
|
|
div = document.createElement('div');
|
|
observer = new MutationObserver(function(m) {
|
|
mutations = m;
|
|
});
|
|
|
|
observer.observe(div, { attributes: true, characterData: true });
|
|
div.appendChild(document.createElement('div'));
|
|
setTimeout(finish, 0);
|
|
}
|
|
|
|
function finish() {
|
|
shouldBe('mutations', 'null');
|
|
observer.disconnect();
|
|
debug('');
|
|
runNextTest();
|
|
}
|
|
|
|
start();
|
|
}
|
|
|
|
function testMultipleRegistration() {
|
|
var div;
|
|
var observer;
|
|
|
|
function start() {
|
|
debug('Testing that re-observing the same node with the same observer has the effect of resetting the options.');
|
|
|
|
calls = 0;
|
|
mutations = null;
|
|
div = document.createElement('div');
|
|
observer = new MutationObserver(function(m) {
|
|
mutations = m;
|
|
calls++;
|
|
});
|
|
|
|
observer.observe(div, { childList: true, characterData: true });
|
|
observer.observe(div, { childList: true });
|
|
div.appendChild(document.createElement('div'));
|
|
setTimeout(checkDisconnectAndMutate, 0);
|
|
}
|
|
|
|
function checkDisconnectAndMutate() {
|
|
shouldBe('calls', '1');
|
|
shouldBe('mutations.length', '1');
|
|
shouldBe('mutations[0].type', '"childList"');
|
|
mutations = null;
|
|
observer.observe(div, { childList: true, characterData: true });
|
|
observer.observe(div, { attributes: true });
|
|
div.appendChild(document.createElement('div'));
|
|
setTimeout(finish, 0);
|
|
}
|
|
|
|
function finish() {
|
|
shouldBe('mutations', 'null');
|
|
observer.disconnect();
|
|
debug('');
|
|
runNextTest();
|
|
}
|
|
|
|
start();
|
|
}
|
|
|
|
function testMultipleObservers() {
|
|
var div;
|
|
var observer;
|
|
var observer2;
|
|
|
|
function start() {
|
|
debug('Testing that multiple observers can be registered to a given node and both receive mutations.');
|
|
mutations = null;
|
|
div = document.createElement('div');
|
|
observer = new MutationObserver(function(m) {
|
|
mutations = m;
|
|
});
|
|
observer2 = new MutationObserver(function(m) {
|
|
mutations2 = m;
|
|
});
|
|
observer.observe(div, { childList: true });
|
|
observer2.observe(div, { childList: true });
|
|
div.appendChild(document.createElement('div'));
|
|
setTimeout(finish, 0);
|
|
}
|
|
|
|
function finish() {
|
|
shouldBe('mutations.length', '1');
|
|
shouldBe('mutations[0].type', '"childList"');
|
|
shouldBe('mutations2.length', '1');
|
|
shouldBe('mutations2[0].type', '"childList"');
|
|
observer.disconnect();
|
|
observer2.disconnect();
|
|
debug('');
|
|
runNextTest();
|
|
}
|
|
|
|
start();
|
|
}
|
|
|
|
function testInnerHTMLAndInnerText() {
|
|
var div;
|
|
var observer;
|
|
|
|
function start() {
|
|
debug('Testing that innerText and innerHTML always result in a single childList mutation.');
|
|
|
|
mutations = null;
|
|
div = document.createElement('div');
|
|
div.innerHTML = '<span>Foo</span><div>Bar</div>';
|
|
removedDiv1 = div.firstChild;
|
|
removedDiv2 = removedDiv1.nextSibling;
|
|
observer = new MutationObserver(function(m) {
|
|
mutations = m;
|
|
});
|
|
|
|
observer.observe(div, { childList: true });
|
|
div.innerHTML = 'foo<img src="bar.png"><p>Baz</p>';
|
|
addedDiv1 = div.childNodes[0];
|
|
addedDiv2 = div.childNodes[1];
|
|
addedDiv3 = div.childNodes[2];
|
|
setTimeout(checkInnerHTML, 0);
|
|
}
|
|
|
|
function checkInnerHTML() {
|
|
debug('...innerHTML');
|
|
|
|
shouldBe('mutations.length', '1');
|
|
shouldBe('mutations[0].type', '"childList"');
|
|
shouldBe('mutations[0].addedNodes.length', '3');
|
|
shouldBe('mutations[0].addedNodes[0]', 'addedDiv1');
|
|
shouldBe('mutations[0].addedNodes[1]', 'addedDiv2');
|
|
shouldBe('mutations[0].addedNodes[2]', 'addedDiv3');
|
|
shouldBe('mutations[0].removedNodes.length', '2');
|
|
shouldBe('mutations[0].removedNodes[0]', 'removedDiv1');
|
|
shouldBe('mutations[0].removedNodes[1]', 'removedDiv2');
|
|
|
|
mutations = null;
|
|
div.innerText = 'foo';
|
|
setTimeout(finish, 0);
|
|
}
|
|
|
|
function finish() {
|
|
debug('...innerText');
|
|
|
|
shouldBe('mutations.length', '1');
|
|
shouldBe('mutations[0].type', '"childList"');
|
|
shouldBe('mutations[0].addedNodes.length', '1');
|
|
shouldBe('mutations[0].removedNodes.length', '3');
|
|
observer.disconnect();
|
|
debug('');
|
|
runNextTest();
|
|
}
|
|
|
|
start();
|
|
}
|
|
|
|
function testReplaceChild() {
|
|
var div;
|
|
var observer;
|
|
var fragment;
|
|
|
|
function start() {
|
|
debug('Testing that replaceChild results in minimal childList mutations.');
|
|
|
|
mutations = null;
|
|
div = document.createElement('div');
|
|
div.innerHTML = '<span>Foo</span><div>Bar</div>';
|
|
removedDiv1 = div.firstChild;
|
|
|
|
observer = new MutationObserver(function(m) {
|
|
mutations = m;
|
|
});
|
|
|
|
observer.observe(div, { childList: true });
|
|
addedDiv1 = document.createElement('div');
|
|
div.replaceChild(addedDiv1, div.firstChild);
|
|
setTimeout(checkReplaceWithNode, 0);
|
|
}
|
|
|
|
function checkReplaceWithNode() {
|
|
debug('...simple replace child');
|
|
|
|
shouldBe('mutations.length', '1');
|
|
shouldBe('mutations[0].type', '"childList"');
|
|
shouldBe('mutations[0].addedNodes.length', '1');
|
|
shouldBe('mutations[0].addedNodes[0]', 'addedDiv1');
|
|
shouldBe('mutations[0].removedNodes.length', '1');
|
|
shouldBe('mutations[0].removedNodes[0]', 'removedDiv1');
|
|
|
|
mutations = null;
|
|
fragment = document.createDocumentFragment();
|
|
addedDiv1 = fragment.appendChild(document.createElement('div'));
|
|
addedDiv2 = fragment.appendChild(document.createElement('div'));
|
|
removedDiv1 = div.firstChild;
|
|
|
|
div.replaceChild(fragment, removedDiv1);
|
|
|
|
setTimeout(finish, 0);
|
|
}
|
|
|
|
function finish() {
|
|
debug('...replace with DocumentFragment');
|
|
|
|
shouldBe('mutations.length', '1');
|
|
shouldBe('mutations[0].type', '"childList"');
|
|
shouldBe('mutations[0].addedNodes.length', '2');
|
|
shouldBe('mutations[0].addedNodes[0]', 'addedDiv1');
|
|
shouldBe('mutations[0].addedNodes[1]', 'addedDiv2');
|
|
shouldBe('mutations[0].removedNodes.length', '1');
|
|
shouldBe('mutations[0].removedNodes[0]', 'removedDiv1');
|
|
|
|
observer.disconnect();
|
|
debug('');
|
|
runNextTest();
|
|
}
|
|
|
|
start();
|
|
}
|
|
|
|
function testInsertBefore() {
|
|
var div;
|
|
var observer;
|
|
var fragment;
|
|
|
|
function start() {
|
|
debug('Testing that insertBefore results in minimal childList mutations.');
|
|
|
|
mutations = null;
|
|
div = document.createElement('div');
|
|
div.innerHTML = '<span>Foo</span>';
|
|
fragment = document.createDocumentFragment();
|
|
addedDiv1 = fragment.appendChild(document.createElement('div'));
|
|
addedDiv2 = fragment.appendChild(document.createElement('div'));
|
|
|
|
observer = new MutationObserver(function(m) {
|
|
mutations = m;
|
|
});
|
|
|
|
observer.observe(div, { childList: true });
|
|
div.insertBefore(fragment, div.firstChild);
|
|
setTimeout(finish, 0);
|
|
}
|
|
|
|
|
|
function finish() {
|
|
shouldBe('mutations.length', '1');
|
|
shouldBe('mutations[0].type', '"childList"');
|
|
shouldBe('mutations[0].addedNodes.length', '2');
|
|
shouldBe('mutations[0].addedNodes[0]', 'addedDiv1');
|
|
shouldBe('mutations[0].addedNodes[1]', 'addedDiv2');
|
|
shouldBe('mutations[0].removedNodes.length', '0');
|
|
|
|
observer.disconnect();
|
|
debug('');
|
|
runNextTest();
|
|
}
|
|
|
|
start();
|
|
}
|
|
|
|
function testAppendChild() {
|
|
var div;
|
|
var observer;
|
|
var fragment;
|
|
|
|
function start() {
|
|
debug('Testing that appendChild results in minimal childList mutations.');
|
|
|
|
mutations = null;
|
|
div = document.createElement('div');
|
|
div.innerHTML = '<span>Foo</span>';
|
|
fragment = document.createDocumentFragment();
|
|
addedDiv1 = fragment.appendChild(document.createElement('div'));
|
|
addedDiv2 = fragment.appendChild(document.createElement('div'));
|
|
|
|
observer = new MutationObserver(function(m) {
|
|
mutations = m;
|
|
});
|
|
|
|
observer.observe(div, { childList: true });
|
|
div.appendChild(fragment);
|
|
setTimeout(finish, 0);
|
|
}
|
|
|
|
function finish() {
|
|
shouldBe('mutations.length', '1');
|
|
shouldBe('mutations[0].type', '"childList"');
|
|
shouldBe('mutations[0].addedNodes.length', '2');
|
|
shouldBe('mutations[0].addedNodes[0]', 'addedDiv1');
|
|
shouldBe('mutations[0].addedNodes[1]', 'addedDiv2');
|
|
shouldBe('mutations[0].removedNodes.length', '0');
|
|
|
|
observer.disconnect();
|
|
debug('');
|
|
runNextTest();
|
|
}
|
|
|
|
start();
|
|
}
|
|
|
|
function testInnerHTMLEmpty() {
|
|
function start() {
|
|
debug('Setting an empty childlist to the empty string with innerHTML should not assert.');
|
|
|
|
var div = document.createElement('div');
|
|
mutations = null;
|
|
observer = new MutationObserver(function(mutations) {
|
|
window.mutations = mutations;
|
|
});
|
|
observer.observe(div, {childList: true});
|
|
div.innerHTML = '';
|
|
setTimeout(finish, 0);
|
|
}
|
|
|
|
function finish() {
|
|
shouldBeNull('mutations');
|
|
debug('');
|
|
runNextTest();
|
|
}
|
|
|
|
start();
|
|
}
|
|
|
|
var tests = [testBasic, testWrongType, testMultipleRegistration, testMultipleObservers, testInnerHTMLAndInnerText, testReplaceChild, testInsertBefore, testAppendChild, testInnerHTMLEmpty];
|
|
var testIndex = 0;
|
|
|
|
function runNextTest() {
|
|
if (testIndex < tests.length)
|
|
tests[testIndex++]();
|
|
else
|
|
finishJSTest();
|
|
}
|
|
|
|
description('Test WebKitMutationObserver.observe on attributes.');
|
|
|
|
runNextTest();
|
|
</script>
|
|
<script src="../../../resources/js-test-post.js"></script>
|
|
</body>
|
|
</html>
|