<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="../../../resources/js-test.js"></script>
</head>
<body>
<p id=description></p>
<div id="console"></div>
<script>
window.jsTestIsAsync = true;
var mutations;
var mutations2;
var mutationsWithOldValue;
var calls;
var charDataNode;
function testBasic() {
var div;
var observer;
function start() {
debug('Testing basic aspects of characterData observation.');
mutations = null;
div = document.createElement('div');
div.textContent = 'foo';
charDataNode = div.firstChild;
observer = new MutationObserver(function(m) {
mutations = m;
});
observer.observe(charDataNode, {characterData: true});
charDataNode.textContent = 'bar';
setTimeout(checkDisconnectAndMutate, 0);
}
function checkDisconnectAndMutate() {
debug('...can characterData changes be observed at all');
shouldBe('mutations.length', '1');
shouldBe('mutations[0].type', '"characterData"');
shouldBe('mutations[0].target', 'charDataNode');
mutations = null;
observer.disconnect();
charDataNode.textContent = 'baz';
setTimeout(checkNotDeliveredAndMutateMultiple, 0);
}
function checkNotDeliveredAndMutateMultiple() {
debug('...observer.disconnect() should prevent further delivery of mutations.');
shouldBe('mutations', 'null');
charDataNode = document.createComment('');
observer.observe(charDataNode, { characterData: true });
charDataNode.textContent = 'foo';
charDataNode.textContent = 'bar';
setTimeout(finish);
}
function finish() {
debug('...re-observing after disconnect works with the same observer.');
shouldBe('mutations.length', '2');
shouldBe('mutations[0].type', '"characterData"');
shouldBe('mutations[0].target', 'charDataNode');
shouldBe('mutations[1].type', '"characterData"');
shouldBe('mutations[1].target', 'charDataNode');
observer.disconnect();
debug('');
runNextTest();
}
start();
}
function testWrongType() {
var div;
var observer;
function start() {
debug('Testing that observing without specifying "characterData" does not result in hearing about characterData changes.');
mutations = null;
div = document.createElement('div');
div.textContent = 'hello';
charDataNode = div.firstChild;
observer = new MutationObserver(function(m) {
mutations = m;
});
observer.observe(charDataNode, {childList: true, attributes: true});
charDataNode = 'goodbye';
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');
div.textContent = 'foo';
charDataNode = div.firstChild;
observer = new MutationObserver(function(m) {
mutations = m;
});
observer2 = new MutationObserver(function(m) {
mutations2 = m;
});
observer.observe(charDataNode, {characterData: true});
observer2.observe(charDataNode, {characterData: true});
charDataNode.textContent = 'bar';
setTimeout(finish, 0);
}
function finish() {
shouldBe('mutations.length', '1');
shouldBe('mutations[0].type', '"characterData"');
shouldBe('mutations[0].target', 'charDataNode');
shouldBe('mutations2.length', '1');
shouldBe('mutations2[0].type', '"characterData"');
shouldBe('mutations2[0].target', 'charDataNode');
observer.disconnect();
observer2.disconnect();
debug('');
runNextTest();
}
start();
}
function testOrderingWrtDOMSubtreeModified() {
var div, div2, subDiv;
var observer;
var listener;
function start() {
debug('Testing mutation records are enqueued for characterData before DOMSubtreeModified is dispatched.');
mutations = null;
div = document.body.appendChild(document.createElement('div'));
div2 = document.body.appendChild(document.createElement('div'));
subDiv = div.appendChild(document.createElement('div'));
subDiv.textContent = 'foo';
charDataNode = subDiv.firstChild;
observer = new MutationObserver(function(m) {
mutations = m;
});
listener = function(e) {
div2.setAttribute('baz', 'bat');
}
div.addEventListener('DOMSubtreeModified', listener);
observer.observe(charDataNode, {characterData: true});
observer.observe(div2, {attributes: true});
charDataNode.textContent = 'bar';
setTimeout(finish, 0);
}
function finish() {
shouldBe('mutations.length', '2');
shouldBe('mutations[0].type', '"characterData"');
shouldBe('mutations[1].type', '"attributes"');
div.removeEventListener('DOMSubtreeModified', listener);
document.body.removeChild(div);
observer.disconnect();
debug('');
runNextTest();
}
start();
}
function testOldValue() {
var div;
var observer;
function start() {
debug('Testing that oldValue is returned when requested.');
mutations = null;
div = document.createElement('div');
div.textContent = 'foo';
charDataNode = div.firstChild;
observer = new MutationObserver(function(mutations) {
window.mutations = mutations;
});
observer.observe(charDataNode, {characterData: true, characterDataOldValue: true});
charDataNode.textContent = 'bar';
charDataNode.textContent = 'baz';
setTimeout(finish, 0);
}
function finish() {
shouldBe('mutations.length', '2');
shouldBe('mutations[0].type', '"characterData"');
shouldBe('mutations[0].target', 'charDataNode');
shouldBe('mutations[0].oldValue', '"foo"');
shouldBe('mutations[1].type', '"characterData"');
shouldBe('mutations[1].target', 'charDataNode');
shouldBe('mutations[1].oldValue', '"bar"');
observer.disconnect();
debug('');
runNextTest();
}
start();
}
function testOldValueAsRequested() {
var div;
var observerWithOldValue;
var observer;
function start() {
debug('Testing that oldValue is delivered as requested (or not).');
mutations = null;
mutationsWithOldValue = null;
div = document.createElement('div');
div.textContent = 'foo';
charDataNode = div.firstChild;
observerWithOldValue = new MutationObserver(function(mutations) {
window.mutationsWithOldValue = mutations;
});
observer = new MutationObserver(function(mutations) {
window.mutations = mutations;
});
observerWithOldValue.observe(charDataNode, {characterData: true, characterDataOldValue: true});
observer.observe(charDataNode, {characterData: true});
charDataNode.textContent = 'bar';
setTimeout(finish, 0);
}
function finish() {
shouldBe('mutationsWithOldValue.length', '1');
shouldBe('mutationsWithOldValue[0].type', '"characterData"');
shouldBe('mutationsWithOldValue[0].oldValue', '"foo"');
shouldBe('mutations.length', '1');
shouldBe('mutations[0].type', '"characterData"');
shouldBe('mutations[0].oldValue', 'null');
observerWithOldValue.disconnect();
observer.disconnect();
debug('');
runNextTest();
}
start();
}
function testOldValueUnionMultipleObservations() {
var div;
var observer;
function start() {
debug('An observer with multiple observations will get characterDataOldValue if any entries request it.');
mutations = null;
div = document.createElement('div');
div.textContent = 'foo';
charDataNode = div.firstChild;
observer = new MutationObserver(function(mutations) {
window.mutations = mutations;
});
observer.observe(div, {characterData: true, characterDataOldValue: true, subtree: true});
observer.observe(charDataNode, {characterData: true});
charDataNode.textContent = 'bar';
setTimeout(finish, 0);
}
function finish() {
shouldBe('mutations.length', '1');
shouldBe('mutations[0].type', '"characterData"');
shouldBe('mutations[0].oldValue', '"foo"');
observer.disconnect();
debug('');
runNextTest();
}
start();
}
var tests = [
testBasic,
testWrongType,
testMultipleObservers,
testOrderingWrtDOMSubtreeModified,
testOldValue,
testOldValueAsRequested,
testOldValueUnionMultipleObservations
];
var testIndex = 0;
function runNextTest() {
if (testIndex < tests.length)
tests[testIndex++]();
else
finishJSTest();
}
description('Test WebKitMutationObserver.observe on CharacterData nodes');
runNextTest();
</script>
</body>
</html>