blob: 6261cf6ab71ac808ddba6f0d989ef6d940686bfd [file] [log] [blame]
<html>
<link rel="import" href="../resources/chai.html" />
<link rel="import" href="../resources/mocha.html" />
<script>
describe('MutationObserver.observe on attributes', function() {
it('should handle basic aspects of attribute observation', function(done) {
var div;
var observer;
var mutations;
function start() {
div = document.createElement('div');
div.setAttribute('bar', 'foo');
observer = new MutationObserver(function(records) {
mutations = records;
});
observer.observe(div, { attributes: true, characterData: true });
div.setAttribute('foo', 'bar');
div.removeAttribute('bar');
setTimeout(checkDisconnectAndMutate, 0);
}
function checkDisconnectAndMutate() {
// ...can attribute changes be observed at all
assert.equal(mutations.length, 2);
assert.equal(mutations[0].type, "attributes");
assert.equal(mutations[0].attributeName, "foo");
assert.equal(mutations[1].type, "attributes");
assert.equal(mutations[1].attributeName, "bar");
mutations = null;
observer.disconnect();
div.setAttribute('foo', 'baz');
setTimeout(checkNotDeliveredAndMutateMultiple, 0);
}
function checkNotDeliveredAndMutateMultiple() {
// ...observer.disconnect() should prevent further delivery of mutations.
assert.equal(mutations, null);
observer.observe(div, { attributes: true });
div.setAttribute('foo', 'bat');
div.setAttribute('bar', 'foo');
setTimeout(finish);
}
function finish() {
// ...re-observing after disconnect works with the same observer.
assert.equal(mutations.length, 2);
assert.equal(mutations[0].type, "attributes");
assert.equal(mutations[0].attributeName, "foo");
assert.equal(mutations[1].type, "attributes");
assert.equal(mutations[1].attributeName, "bar");
observer.disconnect();
done();
}
start();
});
it('should not notify of attribute changes without asking', function(done) {
var div;
var observer;
var mutations;
function start() {
div = document.createElement('div');
observer = new MutationObserver(function(records) {
mutations = records;
});
observer.observe(div, { childList: true, characterData: true });
div.setAttribute('foo', 'bar');
setTimeout(finish, 0);
}
function finish() {
assert.equal(mutations, null);
observer.disconnect();
done();
}
start();
});
it('re-observing the same node with the same observer has the effect of resetting the options', function(done) {
var div;
var observer;
var mutations;
var calls = 0;
function start() {
div = document.createElement('div');
observer = new MutationObserver(function(records) {
mutations = records;
calls++;
});
observer.observe(div, { attributes: true, characterData: true });
observer.observe(div, { attributes: true });
div.setAttribute('foo', 'bar');
setTimeout(checkDisconnectAndMutate, 0);
}
function checkDisconnectAndMutate() {
assert.equal(calls, 1);
assert.equal(mutations.length, 1);
assert.equal(mutations[0].type, "attributes");
assert.equal(mutations[0].attributeName, "foo");
mutations = null;
observer.observe(div, { attributes: true, characterData: true });
observer.observe(div, { childList: true });
div.setAttribute('foo', 'baz');
setTimeout(finish, 0);
}
function finish() {
assert.equal(mutations, null);
observer.disconnect();
done();
}
start();
});
it('multiple observers can be registered to a given node and both receive mutations', function(done) {
var div;
var observer;
var observer2;
var mutations;
var mutations2;
function start() {
div = document.createElement('div');
observer = new MutationObserver(function(records) {
mutations = records;
});
observer2 = new MutationObserver(function(records) {
mutations2 = records;
});
observer.observe(div, { attributes: true });
observer2.observe(div, { attributes: true });
div.setAttribute('foo', 'bar');
setTimeout(finish, 0);
}
function finish() {
assert.equal(mutations.length, 1);
assert.equal(mutations[0].type, "attributes");
assert.equal(mutations[0].attributeName, "foo");
assert.equal(mutations2.length, 1);
assert.equal(mutations2[0].type, "attributes");
assert.equal(mutations2[0].attributeName, "foo");
observer.disconnect();
observer2.disconnect();
done();
}
start();
});
it('should deliver mutations on modifications to node properties which delegate to attribute storage', function(done) {
var img, a;
var observer;
var mutations;
function start() {
img = document.createElement('img');
a = document.createElement('a');
observer = new MutationObserver(function(records) {
mutations = records;
});
observer.observe(img, { attributes: true });
observer.observe(a, { attributes: true });
img.src = 'baz.png';
a.href = 'foo.html';
setTimeout(finish, 0);
}
function finish() {
assert.equal(mutations.length, 2);
assert.equal(mutations[0].type, "attributes");
assert.equal(mutations[0].attributeName, "src");
assert.equal(mutations[1].type, "attributes");
assert.equal(mutations[1].attributeName, "href");
observer.disconnect();
done();
}
start();
});
it('should handle basic oldValue delivery', function(done) {
var div;
var observer;
var mutations;
function start() {
div = document.createElement('div');
div.setAttribute('bar', 'boo');
observer = new MutationObserver(function(records) {
mutations = records;
});
observer.observe(div, { attributes: true, attributeOldValue: true });
div.setAttribute('foo', 'bar');
div.setAttribute('foo', 'baz');
div.removeAttribute('bar');
div.removeAttribute('non-existant');
setTimeout(finish, 0);
}
function finish() {
assert.equal(mutations.length, 3);
assert.equal(mutations[0].type, "attributes");
assert.equal(mutations[0].attributeName, "foo");
assert.equal(mutations[0].oldValue, null);
assert.equal(mutations[1].type, "attributes");
assert.equal(mutations[1].attributeName, "foo");
assert.equal(mutations[1].oldValue, "bar");
assert.equal(mutations[2].type, "attributes");
assert.equal(mutations[2].attributeName, "bar");
assert.equal(mutations[2].oldValue, "boo");
observer.disconnect();
done();
}
start();
});
it('should deliver oldValue when needed', function(done) {
var div;
var observerWithOldValue;
var observer;
var mutationsWithOldValue;
var mutations;
function start() {
div = document.createElement('div');
div.setAttribute('foo', 'bar');
observerWithOldValue = new MutationObserver(function(records) {
mutationsWithOldValue = records;
});
observer = new MutationObserver(function(records) {
mutations = records;
});
observerWithOldValue.observe(div, { attributes: true, attributeOldValue: true });
observer.observe(div, { attributes: true });
div.setAttribute('foo', 'baz');
setTimeout(finish, 0);
}
function finish() {
assert.equal(mutationsWithOldValue.length, 1);
assert.equal(mutationsWithOldValue[0].type, "attributes");
assert.equal(mutationsWithOldValue[0].attributeName, "foo");
assert.equal(mutationsWithOldValue[0].oldValue, "bar");
assert.equal(mutations.length, 1);
assert.equal(mutations[0].type, "attributes");
assert.equal(mutations[0].attributeName, "foo");
assert.equal(mutations[0].oldValue, null);
observerWithOldValue.disconnect();
observer.disconnect();
done();
}
start();
});
it('should give attributeOldValue if any entries request it with multiple observers', function(done) {
var div;
var span;
var observer;
var mutations;
function start() {
div = document.createElement('div');
span = div.appendChild(document.createElement('span'));
span.setAttribute('foo', 'bar');
observer = new MutationObserver(function(records) {
mutations = records;
});
observer.observe(div, { attributes: true, attributeOldValue: true, subtree: true });
observer.observe(span, { attributes: true });
span.setAttribute('foo', 'baz');
setTimeout(finish, 0);
}
function finish() {
assert.equal(mutations.length, 1);
assert.equal(mutations[0].type, "attributes");
assert.equal(mutations[0].attributeName, "foo");
assert.equal(mutations[0].oldValue, "bar");
observer.disconnect();
done();
}
start();
});
it('should handle setting an attribute via reflected IDL attribute', function(done) {
var div;
var observer;
var mutations;
function start() {
div = document.createElement('div');
observer = new MutationObserver(function(records) {
mutations = records;
});
observer.observe(div, { attributes: true, attributeOldValue: true });
div.id = 'foo';
div.id = 'bar';
div.id = null;
setTimeout(finish, 0);
}
function finish() {
assert.equal(mutations.length, 3);
assert.equal(mutations[0].type, "attributes");
assert.equal(mutations[0].attributeName, "id");
assert.equal(mutations[0].oldValue, null);
assert.equal(mutations[1].type, "attributes");
assert.equal(mutations[1].attributeName, "id");
assert.equal(mutations[1].oldValue, "foo");
assert.equal(mutations[2].type, "attributes");
assert.equal(mutations[2].attributeName, "id");
assert.equal(mutations[2].oldValue, "bar");
observer.disconnect();
done();
}
start();
});
it('should respect attributeFilter on HTML elements', function(done) {
var div, path;
var observer;
var mutations;
function start() {
observer = new MutationObserver(function(records) {
mutations = records;
});
div = document.createElement('div');
observer.observe(div, { attributes: true, attributeFilter: ['foo', 'bar', 'booM'] });
div.setAttribute('foo', 'foo');
div.setAttribute('bar', 'bar');
div.setAttribute('baz', 'baz');
div.setAttribute('BOOm', 'boom');
setTimeout(finish, 0);
}
function finish() {
// ...only foo and bar should be received.
assert.equal(mutations.length, 2);
assert.equal(mutations[0].type, "attributes");
assert.equal(mutations[0].attributeName, "foo");
assert.equal(mutations[1].type, "attributes");
assert.equal(mutations[1].attributeName, "bar");
observer.disconnect();
done();
}
start();
});
it('should respect different attributeFilters when observing multiple subtree nodes', function(done) {
var div, div2, div3;
var observer;
var mutations;
function start() {
observer = new MutationObserver(function(records) {
mutations = records;
});
div = document.createElement('div');
div2 = div.appendChild(document.createElement('div'));
div3 = div2.appendChild(document.createElement('div'));
observer.observe(div, { attributes: true, subtree: true, attributeFilter: ['foo', 'bar'] });
observer.observe(div2, { attributes: true, subtree: true, attributeFilter: ['bar', 'bat'] });
div3.setAttribute('foo', 'foo');
div3.setAttribute('bar', 'bar');
div3.setAttribute('bat', 'bat');
div3.setAttribute('baz', 'baz');
setTimeout(checkAndObserveAll, 0);
}
function checkAndObserveAll() {
// ...only foo, bar & bat should be received.
assert.equal(mutations.length, 3);
assert.equal(mutations[0].type, "attributes");
assert.equal(mutations[0].attributeName, "foo");
assert.equal(mutations[1].type, "attributes");
assert.equal(mutations[1].attributeName, "bar");
assert.equal(mutations[2].type, "attributes");
assert.equal(mutations[2].attributeName, "bat");
observer.observe(div2, { attributes: true, subtree: true });
div3.setAttribute('bar', 'bar');
div3.setAttribute('bat', 'bat');
div3.setAttribute('baz', 'baz');
setTimeout(finish, 0);
}
function finish() {
// ...bar, bat & baz should all be received.
assert.equal(mutations.length, 3);
assert.equal(mutations[0].type, "attributes");
assert.equal(mutations[0].attributeName, "bar");
assert.equal(mutations[1].type, "attributes");
assert.equal(mutations[1].attributeName, "bat");
assert.equal(mutations[2].type, "attributes");
assert.equal(mutations[2].attributeName, "baz");
observer.disconnect();
done();
}
start();
});
it('should create records for the style property', function(done) {
var div, path;
var observer;
var mutations;
function start() {
observer = new MutationObserver(function(records) {
mutations = records;
});
div = document.createElement('div');
div.setAttribute('style', 'color: yellow; width: 100px;');
observer.observe(div, { attributes: true });
div.style.color = 'red';
div.style.width = '200px';
div.style.color = 'blue';
setTimeout(checkAndContinue, 0);
}
function checkAndContinue() {
assert.equal(mutations.length, 3);
assert.equal(mutations[0].type, "attributes");
assert.equal(mutations[0].attributeName, "style");
assert.equal(mutations[0].oldValue, null);
assert.equal(mutations[1].type, "attributes");
assert.equal(mutations[1].attributeName, "style");
assert.equal(mutations[1].oldValue, null);
assert.equal(mutations[2].type, "attributes");
assert.equal(mutations[2].attributeName, "style");
assert.equal(mutations[2].oldValue, null);
mutations = null;
div.getAttribute('style');
setTimeout(finish, 0);
}
function finish() {
// ...mutation record created.
assert.equal(mutations, null);
observer.disconnect();
done();
}
start();
});
it('should have oldValue for style property mutations', function(done) {
var div, path;
var observer;
var mutations;
function start() {
observer = new MutationObserver(function(records) {
mutations = records;
});
div = document.createElement('div');
div.setAttribute('style', 'color: yellow; width: 100px;');
observer.observe(div, { attributes: true, attributeOldValue: true });
div.style.color = 'red';
div.style.width = '200px';
div.style.color = 'blue';
setTimeout(checkAndContinue, 0);
}
function checkAndContinue() {
assert.equal(mutations.length, 3);
assert.equal(mutations[0].type, "attributes");
assert.equal(mutations[0].attributeName, "style");
assert.equal(mutations[0].oldValue, "color: yellow; width: 100px;");
assert.equal(mutations[1].type, "attributes");
assert.equal(mutations[1].attributeName, "style");
assert.equal(mutations[1].oldValue, "color: rgb(255, 0, 0); width: 100px;");
assert.equal(mutations[2].type, "attributes");
assert.equal(mutations[2].attributeName, "style");
assert.equal(mutations[2].oldValue, "color: rgb(255, 0, 0); width: 200px;");
mutations = null;
div.getAttribute('style');
setTimeout(finish, 0);
}
function finish() {
// ...mutation record created.
assert.equal(mutations, null);
observer.disconnect();
done();
}
start();
});
it('should not create records for noop style property mutation', function(done) {
var div, path;
var observer;
var mutations;
function start() {
observer = new MutationObserver(function(records) {
mutations = records;
});
div = document.createElement('div');
div.setAttribute('style', 'color: yellow; width: 100px;');
observer.observe(div, { attributes: true });
div.style.removeProperty('height');
setTimeout(finish, 0);
}
function finish() {
assert.equal(mutations, null);
observer.disconnect();
done();
}
start();
});
it('should create records when mutating through the attribute collection', function(done) {
var observer;
var mutations;
var div;
function start() {
observer = new MutationObserver(function(records) {
mutations = records;
});
div = document.createElement('div');
div.setAttribute('data-test', 'foo');
observer.observe(div, { attributes: true, attributeOldValue: true });
div.attributes['data-test'].value = 'bar';
setTimeout(finish, 0);
}
function finish() {
assert.equal(mutations.length, 1);
assert.equal(mutations[0].target, div);
assert.equal(mutations[0].type, "attributes");
assert.equal(mutations[0].attributeName, "data-test");
assert.equal(mutations[0].oldValue, "foo");
observer.disconnect();
done();
}
start();
});
});
</script>
</body>
</html>