306 lines
9.5 KiB
HTML
306 lines
9.5 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;
|
|
var mutations2;
|
|
var div;
|
|
var subDiv, subDiv2, subDiv3, text;
|
|
var calls;
|
|
|
|
function testBasic() {
|
|
var observer;
|
|
|
|
function start() {
|
|
debug('Testing basic aspects of subtree observation.');
|
|
|
|
mutations = null;
|
|
div = document.createElement('div');
|
|
subDiv = div.appendChild(document.createElement('div'));
|
|
subDiv.innerHTML = 'hello, world';
|
|
observer = new MutationObserver(function(mutations) {
|
|
window.mutations = mutations;
|
|
});
|
|
|
|
observer.observe(div, {attributes: true, characterData: true, subtree: true});
|
|
subDiv.setAttribute('foo', 'bar');
|
|
subDiv.firstChild.textContent = 'goodbye!';
|
|
setTimeout(finish, 0);
|
|
}
|
|
|
|
function finish() {
|
|
debug('...attribute and characterData changes in subtree');
|
|
|
|
shouldBe('mutations.length', '2');
|
|
shouldBe('mutations[0].type', '"attributes"');
|
|
shouldBe('mutations[0].target', 'subDiv');
|
|
shouldBe('mutations[0].attributeName', '"foo"');
|
|
shouldBe('mutations[0].attributeNamespace', 'null');
|
|
shouldBe('mutations[1].type', '"characterData"');
|
|
shouldBe('mutations[1].target', 'subDiv.firstChild');
|
|
observer.disconnect();
|
|
debug('');
|
|
runNextTest();
|
|
}
|
|
|
|
start();
|
|
}
|
|
|
|
function testMultipleObservers() {
|
|
var observer;
|
|
var observer2;
|
|
|
|
function start() {
|
|
debug('Testing two observers at different depths.');
|
|
|
|
mutations = null;
|
|
mutations2 = null;
|
|
div = document.createElement('div');
|
|
subDiv = div.appendChild(document.createElement('div'));
|
|
observer = new MutationObserver(function(mutations) {
|
|
window.mutations = mutations;
|
|
});
|
|
observer2 = new MutationObserver(function(mutations) {
|
|
window.mutations2 = mutations;
|
|
});
|
|
|
|
observer.observe(div, {attributes: true, subtree: true});
|
|
observer2.observe(subDiv, {attributes: true});
|
|
subDiv.setAttribute('foo', 'bar');
|
|
setTimeout(finish, 0);
|
|
}
|
|
|
|
function finish() {
|
|
shouldBe('mutations.length', '1');
|
|
shouldBe('mutations[0].type', '"attributes"');
|
|
shouldBe('mutations[0].target', 'subDiv');
|
|
shouldBe('mutations[0].attributeName', '"foo"');
|
|
shouldBe('mutations[0].attributeNamespace', 'null');
|
|
shouldBe('mutations2.length', '1');
|
|
shouldBe('mutations2[0].type', '"attributes"');
|
|
shouldBe('mutations2[0].target', 'subDiv');
|
|
shouldBe('mutations2[0].attributeName', '"foo"');
|
|
shouldBe('mutations2[0].attributeNamespace', 'null');
|
|
observer.disconnect();
|
|
observer2.disconnect();
|
|
debug('');
|
|
runNextTest();
|
|
}
|
|
|
|
start();
|
|
}
|
|
|
|
function testMultipleObservations() {
|
|
var observer;
|
|
|
|
function start() {
|
|
debug('Testing one observer at two different depths.');
|
|
|
|
mutations = null;
|
|
calls = 0;
|
|
div = document.createElement('div');
|
|
subDiv = div.appendChild(document.createElement('div'));
|
|
observer = new MutationObserver(function(mutations) {
|
|
window.mutations = mutations;
|
|
++calls;
|
|
});
|
|
|
|
observer.observe(div, {attributes: true, subtree: true});
|
|
observer.observe(subDiv, {attributes: true, subtree: true});
|
|
subDiv.setAttribute('foo', 'bar');
|
|
setTimeout(finish, 0);
|
|
}
|
|
|
|
function finish() {
|
|
shouldBe('calls', '1');
|
|
shouldBe('mutations.length', '1');
|
|
shouldBe('mutations[0].type', '"attributes"');
|
|
shouldBe('mutations[0].target', 'subDiv');
|
|
shouldBe('mutations[0].attributeName', '"foo"');
|
|
shouldBe('mutations[0].attributeNamespace', 'null');
|
|
observer.disconnect();
|
|
debug('');
|
|
runNextTest();
|
|
}
|
|
|
|
start();
|
|
}
|
|
|
|
function testTransientDetachedBasic() {
|
|
var observer;
|
|
|
|
function start() {
|
|
debug('Testing that transiently detached nodes are still observed via subtree.');
|
|
|
|
mutations = null;
|
|
div = document.createElement('div');
|
|
subDiv = div.appendChild(document.createElement('div'));
|
|
subDiv.innerHTML = 'hello, world';
|
|
observer = new MutationObserver(function(mutations) {
|
|
window.mutations = mutations;
|
|
});
|
|
|
|
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() {
|
|
debug('...both changes should be received. Change detached subDiv again.');
|
|
|
|
shouldBe('mutations.length', '2');
|
|
shouldBe('mutations[0].type', '"attributes"');
|
|
shouldBe('mutations[0].target', 'subDiv');
|
|
shouldBe('mutations[0].attributeName', '"foo"');
|
|
shouldBe('mutations[1].type', '"attributes"');
|
|
shouldBe('mutations[1].target', 'subDiv');
|
|
shouldBe('mutations[1].attributeName', '"test"');
|
|
|
|
mutations = null;
|
|
subDiv.setAttribute('foo', 'baz');
|
|
|
|
setTimeout(checkNotDeliveredAndReattach);
|
|
}
|
|
|
|
function checkNotDeliveredAndReattach() {
|
|
debug('...transient subtree observation was stopped after delivery, so subDiv change should not be received. Reattach and change again.');
|
|
|
|
shouldBe('mutations', 'null');
|
|
|
|
mutations = null
|
|
div.appendChild(subDiv);
|
|
subDiv.setAttribute('foo', 'bat');
|
|
|
|
setTimeout(checkDeliveredAndReobserve);
|
|
}
|
|
|
|
function checkDeliveredAndReobserve() {
|
|
debug('...reattached subtree should now be observable. Try detaching and re-observing.');
|
|
|
|
shouldBe('mutations.length', '1');
|
|
shouldBe('mutations[0].type', '"attributes"');
|
|
shouldBe('mutations[0].target', 'subDiv');
|
|
shouldBe('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);
|
|
}
|
|
|
|
|
|
function finish() {
|
|
debug('...The change made before re-observing should be received, but not the one after.');
|
|
|
|
shouldBe('mutations.length', '1');
|
|
shouldBe('mutations[0].type', '"characterData"');
|
|
shouldBe('mutations[0].target', 'subDiv.firstChild');
|
|
|
|
observer.disconnect();
|
|
debug('');
|
|
runNextTest();
|
|
}
|
|
start();
|
|
}
|
|
|
|
function testTransientDetachedDetailed() {
|
|
var observer;
|
|
|
|
function start() {
|
|
debug('Testing correct behavior of transient observation with complex movement .');
|
|
|
|
mutations = null;
|
|
div = document.createElement('div');
|
|
subDiv = div.appendChild(document.createElement('div'));
|
|
subDiv2 = subDiv.appendChild(document.createElement('div'));
|
|
subDiv2.innerHTML = 'hello, world';
|
|
subDiv3 = document.createElement('div');
|
|
|
|
observer = new MutationObserver(function(mutations) {
|
|
window.mutations = mutations;
|
|
});
|
|
|
|
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() {
|
|
debug('...All changes should be received except for setting the "d" attribute on subDiv3 before it was reachable from div.');
|
|
|
|
shouldBe('mutations.length', '6');
|
|
shouldBe('mutations[0].type', '"attributes"');
|
|
shouldBe('mutations[0].target', 'subDiv');
|
|
shouldBe('mutations[0].attributeName', '"a"');
|
|
|
|
shouldBe('mutations[1].type', '"attributes"');
|
|
shouldBe('mutations[1].target', 'subDiv2');
|
|
shouldBe('mutations[1].attributeName', '"b"');
|
|
|
|
shouldBe('mutations[2].type', '"characterData"');
|
|
shouldBe('mutations[2].target', 'text');
|
|
|
|
shouldBe('mutations[3].type', '"attributes"');
|
|
shouldBe('mutations[3].target', 'subDiv2');
|
|
shouldBe('mutations[3].attributeName', '"e"');
|
|
|
|
shouldBe('mutations[4].type', '"attributes"');
|
|
shouldBe('mutations[4].target', 'subDiv3');
|
|
shouldBe('mutations[4].attributeName', '"f"');
|
|
|
|
shouldBe('mutations[5].type', '"attributes"');
|
|
shouldBe('mutations[5].target', 'subDiv2');
|
|
shouldBe('mutations[5].attributeName', '"g"');
|
|
|
|
observer.disconnect();
|
|
debug('');
|
|
runNextTest();
|
|
}
|
|
start();
|
|
}
|
|
|
|
var tests = [testBasic, testMultipleObservers, testMultipleObservations, testTransientDetachedBasic, testTransientDetachedDetailed];
|
|
var testIndex = 0;
|
|
|
|
function runNextTest() {
|
|
if (testIndex < tests.length)
|
|
tests[testIndex++]();
|
|
else
|
|
finishJSTest();
|
|
}
|
|
|
|
description('Test WebKitMutationObserver.observe on a subtree');
|
|
|
|
runNextTest();
|
|
</script>
|
|
<script src="../../../resources/js-test-post.js"></script>
|
|
</body>
|
|
</html>
|