blob: 51627d0050021ef63385275133bd1049d100e278 [file] [log] [blame]
/*
* Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
* for details. All rights reserved. Use of this source code is governed by a
* BSD-style license that can be found in the LICENSE file.
*/
/**
* @description Test WebKitMutationObserver.observe on a subtree
*/
import "dart:html";
import "../../../../Utils/expect.dart";
import "../../../../Utils/async_utils.dart";
import "../../../testcommon.dart";
main() {
var mutations;
var mutations2;
var div;
var subDiv, subDiv2, subDiv3, text;
var calls;
var runNextTest;
testBasic() {
var observer;
var finish;
start() {
debug('Testing basic aspects of subtree observation.');
mutations = null;
div = document.createElement('div');
subDiv = div.append(document.createElement('div'));
subDiv.innerHtml = 'hello, world';
observer = new MutationObserver((m,o) {
mutations = m;
});
observer.observe(div, attributes: true, characterData: true, subtree: true);
subDiv.setAttribute('foo', 'bar');
subDiv.firstChild.text = 'goodbye!';
setTimeout(finish, 0);
}
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();
}
testMultipleObservers() {
var observer;
var observer2;
var finish;
start() {
debug('Testing two observers at different depths.');
mutations = null;
mutations2 = null;
div = document.createElement('div');
subDiv = div.append(document.createElement('div'));
observer = new MutationObserver((m,o) {
mutations = m;
});
observer2 = new MutationObserver((m,o) {
mutations2 = m;
});
observer.observe(div, attributes: true, subtree: true);
observer2.observe(subDiv, attributes: true);
subDiv.setAttribute('foo', 'bar');
setTimeout(finish, 0);
}
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();
}
testMultipleObservations() {
var observer;
var finish;
start() {
debug('Testing one observer at two different depths.');
mutations = null;
calls = 0;
div = document.createElement('div');
subDiv = div.append(document.createElement('div'));
observer = new MutationObserver((m,o) {
mutations = m;
++calls;
});
observer.observe(div, attributes: true, subtree: true);
observer.observe(subDiv, attributes: true, subtree: true);
subDiv.setAttribute('foo', 'bar');
setTimeout(finish, 0);
}
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();
}
testTransientDetachedBasic() {
var observer;
var checkDeliveredAndChangeAgain;
var checkNotDeliveredAndReattach;
var checkDeliveredAndReobserve;
var finish;
start() {
debug('Testing that transiently detached nodes are still observed via subtree.');
mutations = null;
div = document.createElement('div');
subDiv = div.append(document.createElement('div'));
subDiv.innerHtml = 'hello, world';
observer = new MutationObserver((m,o) {
mutations = m;
});
observer.observe(div, attributes: true, characterData: true, subtree: true);
subDiv.setAttribute('foo', 'bar');
subDiv.remove();
subDiv.setAttribute('test', 'test');
setTimeout(checkDeliveredAndChangeAgain, 0);
}
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);
};
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.append(subDiv);
subDiv.setAttribute('foo', 'bat');
setTimeout(checkDeliveredAndReobserve);
};
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;
subDiv.remove();
subDiv.firstChild.text = 'badbye';
observer.observe(div, attributes: true, characterData: true, subtree: true);
subDiv.setAttribute('foo', 'boo');
setTimeout(finish);
};
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();
}
testTransientDetachedDetailed() {
var observer;
var finish;
start() {
debug('Testing correct behavior of transient observation with complex movement .');
mutations = null;
div = document.createElement('div');
subDiv = div.append(document.createElement('div'));
subDiv2 = subDiv.append(document.createElement('div'));
subDiv2.innerHtml = 'hello, world';
subDiv3 = document.createElement('div');
observer = new MutationObserver((m,o) {
mutations = m;
});
observer.observe(div, attributes: true, characterData: true, subtree: true);
subDiv.remove();
subDiv2.remove();
text = subDiv2.firstChild..remove();
subDiv.setAttribute('a', 'a');
subDiv2.setAttribute('b', 'b');
text.text = 'c';
subDiv3.append(subDiv2);
subDiv3.setAttribute('d', 'd');
subDiv2.setAttribute('e', 'e');
div.append(subDiv3);
subDiv3.setAttribute('f', 'f');
subDiv2.setAttribute('g', 'g');
setTimeout(finish, 0);
}
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;
runNextTest = () {
if (testIndex < tests.length)
tests[testIndex++]();
else
asyncEnd();
};
asyncStart();
runNextTest();
}