I want to synchronize some DOM node attributes. If an attribute is changed then it changes other elements attribute.
I can change it but I cannot write an test for it. The test changes the attribute of the observed element and then checks if the changes where applied to other elements. The change sync will eventually happen, but not immediately after the observed element attribute change.
In this example I've created three divs and want to synchronize the class attribute of #div1
to other two.
html:
<div id="div1" class="foo"></div>
<div id="div2" class="foo"></div>
<div id="div3" class="foo"></div>
js:
let div1 = document.getElementById("div1")
let div2 = document.getElementById("div2")
let div3 = document.getElementById("div3")
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
console.log(mutation.target.getAttribute("class"))
//sync the new attribute value to
div2.setAttribute("class", mutation.target.getAttribute("class"))
div3.setAttribute("class", mutation.target.getAttribute("class"))
})
})
// pass in the target node, as well as the observer options
observer.observe(div1, { attributes: true, attributeFilter: ["class"]})
//the test sets the class attribute of div1 to 'bar'
div1.setAttribute("class", "bar")
//then checks if div2 and div3 class is set to 'bar'
console.log("is div2.class = 'bar'?", div2.getAttribute("class") == "bar")
console.log("is div3.class = 'bar'?", div3.getAttribute("class") == "bar")
the output is:
is div2.class = 'bar'? false
is div3.class = 'bar'? false
bar
MutationObserver
runs only after the checks and then the div2.class
and div3.class
are set to 'bar'
. So my question is, how to test the synchronization of attributes with MutationObserver
.
You need to wait for the mutation observer to handle the mutation event before you check for the updated classes.
The common trick is to use a setTimeout
. See this question for how it works.
let div1 = document.getElementById("div1");
let div2 = document.getElementById("div2");
let div3 = document.getElementById("div3");
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
console.log(mutation.target.getAttribute("class"));
div2.setAttribute("class", mutation.target.getAttribute("class"));
div3.setAttribute("class", mutation.target.getAttribute("class"));
});
});
// pass in the target node, as well as the observer options
observer.observe(div1, {
attributes: true,
attributeFilter: ["class"]
});
function testMutationObserver(mutation, afterMutation) {
//Perform the mutation, e.g. by setting a new class
mutation();
//setTimeout gives the MutationObserver a chance to see the changes
setTimeout(afterMutation);
}
testMutationObserver(
function() {
div1.setAttribute("class", "bar");
},
function() {
console.log("is div2.class = 'bar'?", div2.getAttribute("class") == "bar");
console.log("is div3.class = 'bar'?", div3.getAttribute("class") == "bar");
}
);
<div id="div1" class="foo"></div>
<div id="div2" class="foo"></div>
<div id="div3" class="foo"></div>