public void MutationObserverCharacterdataCallback()
        {
            var document = Html("");
            var div      = document.CreateElement("div");
            var child    = div.AppendChild(document.CreateTextNode("text"));
            var i        = 0;
            var observer = new MutationObserver((records, obs) =>
            {
                Assert.LessOrEqual(++i, 2);
                Assert.AreEqual(1, records.Count());

                AssertRecord(records[0], new TestMutationRecord
                {
                    Type   = "characterData",
                    Target = child
                });

                // The transient observers are removed before the callback is called.
                child.TextContent += " again";
                records            = obs.Flush().ToArray();
                Assert.AreEqual(0, records.Count());
            });

            observer.Connect(div, characterData: true, subtree: true);
            div.RemoveChild(child);
            child.TextContent = "changed";
            observer.Trigger();
        }
        public void MutationObserverAttrCallback()
        {
            var document = Html("");
            var testDiv  = document.Body.AppendChild(document.CreateElement("div"));
            var div      = testDiv.AppendChild(document.CreateElement("div"));
            var child    = document.CreateElement("div");

            div.AppendChild(child);
            var i        = 0;
            var observer = new MutationObserver((records, obs) =>
            {
                Assert.LessOrEqual(++i, 2);
                Assert.AreEqual(1, records.Count());

                AssertRecord(records[0], new TestMutationRecord
                {
                    Type               = "attributes",
                    Target             = child,
                    AttributeName      = "a",
                    AttributeNamespace = null
                });

                // The transient observers are removed before the callback is called.
                child.SetAttribute("b", "B");
                records = obs.Flush().ToArray();
                Assert.AreEqual(0, records.Count());
            });

            observer.Connect(div, attributes: true, subtree: true);

            div.RemoveChild(child);
            child.SetAttribute("a", "A");
            observer.Trigger();
        }
        public void MutationObserverAttrMakeSureTransientGetsRemoved()
        {
            var document = Html("");
            var testDiv  = document.Body.AppendChild(document.CreateElement("div"));
            var div      = testDiv.AppendChild(document.CreateElement("div"));
            var child    = document.CreateElement("div");

            div.AppendChild(child);
            var i        = 0;
            var observer = new MutationObserver((records, obs) =>
            {
                Assert.AreNotEqual(2, ++i);
                Assert.AreEqual(records.Count(), 1);

                AssertRecord(records[0], new TestMutationRecord
                {
                    Type               = "attributes",
                    Target             = child,
                    AttributeName      = "a",
                    AttributeNamespace = null
                });
            });

            observer.Connect(div, subtree: true, attributes: true);

            div.RemoveChild(child);
            child.SetAttribute("a", "A");
            observer.Trigger();

            var div2      = document.CreateElement("div");
            var observer2 = new MutationObserver((records, obs) =>
            {
                Assert.LessOrEqual(++i, 3);
                Assert.AreEqual(records.Count(), 1);

                AssertRecord(records[0], new TestMutationRecord
                {
                    Type               = "attributes",
                    Target             = child,
                    AttributeName      = "b",
                    AttributeNamespace = null
                });
            });

            observer2.Connect(div2, attributes: true, subtree: true);

            div2.AppendChild(child);
            child.SetAttribute("b", "B");
            observer2.Trigger();
        }
        public async Task MutationObserverChildlistCallback()
        {
            var document   = Html("", true);
            var testDiv    = document.Body.AppendChild(document.CreateElement("div"));
            var div        = testDiv.AppendChild(document.CreateElement("div"));
            var child      = div.AppendChild(document.CreateElement("div"));
            var grandChild = document.CreateElement("span");
            var i          = 0;
            var tcs        = new TaskCompletionSource <Boolean>();
            var observer   = new MutationObserver((records, obs) =>
            {
                Assert.LessOrEqual(++i, 2);
                Assert.AreEqual(2, records.Count());

                AssertRecord(records[0], new TestMutationRecord
                {
                    Type    = "childList",
                    Target  = div,
                    Removed = ToNodeList(child)
                });

                AssertRecord(records[1], new TestMutationRecord
                {
                    Type   = "childList",
                    Target = child,
                    Added  = ToNodeList(grandChild)
                });

                // The transient observers are removed before the callback is called.
                child.RemoveChild(grandChild);

                records = obs.Flush().ToArray();
                Assert.AreEqual(0, records.Count());
                tcs.SetResult(true);
            });

            observer.Connect(div, childList: true, subtree: true);
            div.RemoveChild(child);
            child.AppendChild(grandChild);
            observer.Trigger();
            await tcs.Task.ConfigureAwait(false);
        }